library(dplyr)
Attaching package: ‘dplyr’
The following objects are masked from ‘package:stats’:
filter, lag
The following objects are masked from ‘package:base’:
intersect, setdiff, setequal, union
library(ggplot2)
library(forcats)
library(here)
here() starts at /Users/avrilwang/Desktop/Project-Plasmodium
library(deSolve)
library(crone)
library(optimParallel)
Loading required package: parallel
library(doParallel)
Loading required package: foreach
Loading required package: iterators
library(doRNG)
Loading required package: rngtools
library(arrow)
Attaching package: ‘arrow’
The following object is masked from ‘package:utils’:
timestamp
library(stringr)
library(parallel)
library(ggpubr)
library(scales)
Notebook for plotting all of the figures for PloS Biology manuscript submission
Guidelines: taken from https://journals.plos.org/plosbiology/s/figures#loc-figure-file-requirements 1. format: eps 2. max file size: 10 MB 3. text size: Arial, Times, or Symbol font only in 8-12 point 2. figure size: Width: 789 – 2250 pixels (at 300 dpi). Height maximum: 2625 pixels (at 300 dpi).
#=========================================# figure 1: best single and co-infection cue #=========================================# Figure displaying the reaction norms of best single and co-infection.
#——- optimal cue reaction norm ———–# # read data
process data for reaction norm
# import labelling scheme
ez_label <- read.csv(here("data/ez_label.csv"))
# get si_label with ci cue range
si_ci_rug.df <- ci_rug.df %>%
mutate(label_si = case_when(
label %in% c("I", "I1+I2") ~ "I",
label %in% c("I log","I1+I2 log") ~ "I log",
label %in% c("Ig", "Ig1+Ig2") ~ "Ig",
label %in% c("Ig log") ~ "Ig log",
label %in% c("sum", "I+Ig") ~ "I+Ig",
label %in% c("sum log", "I+Ig log") ~ "I+Ig log",
label == "R" ~ "R",
label == "R log" ~ "R log",
label %in% c("G", "G1+G2") ~ "G",
label == "G log" ~ "G log"
))
# get limit for si_rug
si_rug_lim.df <- si_rug.df %>%
filter(time <= 20) %>%
group_by(label)%>%
summarise(min = min(value, na.rm = T)*0.9,
max = max(value, na.rm = T)*1.1) %>%
select(label_si = label, min_si = min, max_si = max)
# filter to restriction conversion rate reaction norm range to cue ranges that appear in rug
## change to Inf/-inf to NA. Note that I am first joining with si rug lim to check which limit is larger, We will go with the cue range that has the largest span
ci_rug_lim.df <- si_ci_rug.df %>%
group_by(label) %>%
mutate(min = min(value, na.rm = T)*0.9,
max = max(value, na.rm = T)*1.1) %>%
distinct(label, .keep_all = T) %>%
select(label, label_si, min, max)
rug_lim.final <- ci_rug_lim.df %>% left_join(si_rug_lim.df, by = "label_si") %>%
mutate(final_min = min(min, min_si),
final_max = max(max, max_si))
# get second rug_lim.final for single infection
rug_lim.final2 <- rug_lim.final %>%
group_by(label_si) %>%
mutate(final_min = min(final_min, na.rm = T),
final_max = max(final_max, na.rm = T))
# filter ci_rn by limit
ci_rn.df2 <- ci_rn.df %>%
left_join(rug_lim.final, by = "label") %>%
group_by(label) %>%
filter(cue_range <= final_max & cue_range >= final_min) %>%
arrange(cue_range, .by_group = T) %>%
filter(row_number() %% 10 == 0)
# import labelling scheme
ez_label <- read.csv(here("data/ez_label.csv"))
match single infection rn with coinfection
# get ci label to si rug and filter by limit
si_rn.df2 <- left_join(si_rn.df, select(ez_label, label_si, label_ci), by = c("label" = "label_si")) %>%
left_join(rug_lim.final, by = c("label_ci" = "label")) %>%
group_by(label_ci) %>%
filter(cue_range <= final_max & cue_range >= final_min) %>%
arrange(cue_range, .by_group = T) %>%
filter(row_number() %% 10 == 0) %>%
select(cue_range, cr, label_ci, label_si)
Warning in left_join(si_rn.df, select(ez_label, label_si, label_ci), by = c(label = "label_si")) :
Detected an unexpected many-to-many relationship between `x` and `y`.
ℹ Row 1 of `x` matches multiple rows in `y`.
ℹ Row 1 of `y` matches multiple rows in `x`.
ℹ If a many-to-many relationship is expected, set `relationship = "many-to-many"` to silence this warning.
# get ci label to si rug, we will keep one unique value per label
si_rug.df2 <- select(si_rug.df, value, label_si = label) %>% distinct(value, label_si)
plot reaction norm
# join with ezlabel
ci_rn.df3 <- ci_rn.df2 %>% left_join(ez_label, by = c("label" = "label_ci"))
si_rn.df3 <- si_rn.df2 %>% left_join(ez_label, by = "label_ci")
ci_rug.df3 <- ci_rug.df %>% left_join(ez_label, by = c("label" = "label_ci"))
si_rug.df3 <- si_rug.df2 %>% left_join(ez_label, by = "label_si")
Warning in left_join(., ez_label, by = "label_si") :
Detected an unexpected many-to-many relationship between `x` and `y`.
ℹ Row 27002 of `x` matches multiple rows in `y`.
ℹ Row 12 of `y` matches multiple rows in `x`.
ℹ If a many-to-many relationship is expected, set `relationship = "many-to-many"` to silence this warning.
# redo order of cues
ci_rn.df3$ez_label <- factor(ci_rn.df3$ez_label,
levels = c("Asexual iRBC", "Asexual iRBC log10",
"Total asexual iRBC", "Total asexual\niRBC log10",
"Sexual iRBC", "Sexual iRBC log10",
"Asexual&sexual iRBC", "Asexual&sexual\niRBC log10",
"Total iRBC", "Total iRBC log10",
"Gametocyte", "Gametocyte log10",
"Total gametocyte", "Total sexual iRBC",
"RBC", "RBC log10"))
si_rn.df3$ez_label <- factor(si_rn.df3$ez_label,
levels = c("Asexual iRBC", "Asexual iRBC log10",
"Total asexual iRBC", "Total asexual\niRBC log10",
"Sexual iRBC", "Sexual iRBC log10",
"Asexual&sexual iRBC", "Asexual&sexual\niRBC log10",
"Total iRBC", "Total iRBC log10",
"Gametocyte", "Gametocyte log10",
"Total gametocyte", "Total sexual iRBC",
"RBC", "RBC log10"))
ci_rug.df3$ez_label <- factor(ci_rug.df3$ez_label,
levels = c("Asexual iRBC", "Asexual iRBC log10",
"Total asexual iRBC", "Total asexual\niRBC log10",
"Sexual iRBC", "Sexual iRBC log10",
"Asexual&sexual iRBC", "Asexual&sexual\niRBC log10",
"Total iRBC", "Total iRBC log10",
"Gametocyte", "Gametocyte log10",
"Total gametocyte", "Total sexual iRBC",
"RBC", "RBC log10"))
si_rug.df3$ez_label <- factor(si_rug.df3$ez_label,
levels = c("Asexual iRBC", "Asexual iRBC log10",
"Total asexual iRBC", "Total asexual\niRBC log10",
"Sexual iRBC", "Sexual iRBC log10",
"Asexual&sexual iRBC", "Asexual&sexual\niRBC log10",
"Total iRBC", "Total iRBC log10",
"Gametocyte", "Gametocyte log10",
"Total gametocyte", "Total sexual iRBC",
"RBC", "RBC log10"))
# plot
ggplot() +
geom_line(data = ci_rn.df3, aes(x = cue_range, y = cr, color = "Co-infection")) +
geom_point(data = ci_rn.df3 %>%
group_by(label) %>%
mutate(ten_th = round(n()/10)) %>%
filter(row_number() %% ten_th == 0), aes(x = cue_range, y = cr, color = "Co-infection", shape = "Co-infection"), size = 2) +
geom_line(data = si_rn.df3, aes(x = cue_range, y = cr, color = "Single infection")) +
geom_point(data = si_rn.df3 %>%
group_by(label_ci) %>%
mutate(ten_th = round(n()/10)) %>%
filter(row_number() %% ten_th == 0), aes(x = cue_range, y = cr, color = "Single infection", shape = "Single infection"), size = 2) +
geom_rug(data = ci_rug.df3, aes(x = value), color = "#4575b4", sides = "t", length = unit(0.1, "npc")) +
geom_rug(data = si_rug.df3, aes(x = value), color = "#fc8d59", sides = "b", length = unit(0.1, "npc")) +
facet_wrap(~ez_label, scales = "free_x", ncol = 2) +
ylim(-0.3, 1.3) +
theme_bw() +
labs(y = "Conversion rate", x = "Cue range", color = "Model", shape = "Model") +
scale_x_continuous(labels = function(x) format(x, scientific = T),
guide = guide_axis(check.overlap = TRUE)) +
theme(axis.text.x = element_text(size = 7),
legend.position = "right") +
scale_color_manual(values=c( "#4575b4", "#fc8d59")) +
theme(strip.text.x = element_text(margin = margin(b = 0.5, t = 0.5)))
ggsave(units = "px", dpi = 300, width = 2000, height = 2500, filename = here("figures/plos-bio/reaction_norm.tiff"), bg = "white", scale = 1.1)

#=========================================# Plotting single and co-infection fitness scatter plot #=========================================# # import in data
# single infection dynamics
si_dyn.df <- read_parquet(here("data/si_dyn/si_dyn_30.parquet"))
# co-infection dynamics
ci_dyn.df <- read_parquet(here("data/ci_dyn/ci_dyn.parquet"))
ez_label <- read.csv(here("data/ez_label.csv"))
process for final 20 days fitness
d
Error: object 'd' not found
plot scatter point of single infection vs co-infection
si_ci_fitness.pl <- ggplot() +
geom_point(data = si_ci_fitness.df, aes(x = fitness_si, y = fitness_ci, color = ez_label_si, shape = ez_label_si), size = 3.5) +
ggrepel::geom_label_repel(data = si_ci_fitness.df, aes(label = ez_label, x = fitness_si, y = fitness_ci),
fill = "white",xlim = c(-Inf, Inf), ylim = c(NA, NA)) +
labs(x = "Maximum single infection fitness", y = "Maximum Co-infection fitness (per strain)",
color = "Single infection cue", shape = "Single infection cue") +
scale_shape_manual(values = 15:25) +
lims(x = c(8, 10.3)) +
theme_bw()
#=========================================================# # time series conversion rate for single and co-infection #=========================================================# #———get “ideal” single infection and co-infection dynamics———# This is when stuff are optimized based on time
source(here("functions/chabaudi_si_clean.R"))
source(here("functions/chabaudi_ci_clean.R"))
# single infection dynamic with time as cue. Optimized using local optimizer. Note that the time variable in dual cue is slightly different with higher flexibility. While that increases the fitness value by ~0.1, the overall conversion rate dynamic does not change that much
si_t.df <- chabaudi_si_clean(
parameters_cr = c(4.55386, -13.0056, 4.15466, -11.9424),
immunity = "tsukushi",
parameters = parameters_tsukushi,
time_range = seq(0, 20, by = 1e-3),
cue_range = seq(0, 20, by = 1e-3),
cue = "t",
solver = "vode",
dyn = T)
# co-infection dynamic with time as cue
ci_t.df <- chabaudi_ci_clean(parameters_cr_1 = c(26.16425, -71.07799, 53.34121, -166.25693),
parameters_cr_2 = c(26.16425, -71.07799, 53.34121, -166.25693),
immunity = "tsukushi",
parameters = parameters_tsukushi,
time_range = time_range,
cue_1 = "t",
cue_2= "t",
cue_range_1 = time_range, # cue range of strain 1
cue_range_2 = time_range, # cue range of strain 2
log_cue_1 = "none", # whether to log transform cue 1
log_cue_2 = "none", # whether to log transform cue 2
solver = "vode", # solver for numerical integration. Vode often gives faster runs
dyn = T)
# get only conversion rate and make same format as si_cr.df2/ci_cr.df2
si_t.df %>% filter(time == 20 & variable == "tau_cum") ## fitness value of time as cue in single infection
si_t.cr <- si_t.df %>%
filter(variable == "cr") %>%
mutate(ez_label_si = "Time",
fitness_si =9.787899) %>%
select(time, value, fitness_si, ez_label_si)
## get fitness value of co-infection time
ci_t.df %>% filter(variable == "tau_cum1") %>% summarize(max = max(value, na.rm = T))
ci_t.cr <- ci_t.df %>%
filter(variable == "cr_1") %>%
mutate(ez_label = "Time",
fitness_ci = 2.311841) %>%
select(time, value, fitness_ci, ez_label)
#——— single infection conversion rate heat map————–# # process info for single infection
—————–co-infection conversion rate heatmap———–
plot co-infeciton convesion rate heatmap
ggplot() +
geom_raster(data = ci_cr.df2,
aes(x = time, y = forcats::fct_reorder(ez_label, fitness_ci), fill = value)) +
labs(x = "Time (days)", y = "Co-infection cues", fill = "Conversion rate") +
viridis::scale_fill_viridis(limits = c(0, 1), , oob = scales::squish) +
xlim(1, 20) +
theme_bw()
Warning: Removed 17028 rows containing missing values (`geom_raster()`).

#——— assemble final figure ————–#
# combine conversion rate dynamic of single infection and co-infection
cr.pl <- ggarrange(si_cr.pl, ci_cr.pl, labels = c("B", "C"), ncol = 2, common.legend = T, align = "h")
# combine with fitness scatterplot
ggarrange(si_ci_fitness.pl, cr.pl, ncol = 1, labels = c("A", ""), align = "hv")
# save
ggsave(units = "px", dpi = 300, width = 2000, height = 2000, filename = here("figures/plos-bio/fitness_cr-dyn.tiff"), bg = "white", scale = 1.35)
#===========================================================# # Demographic stochasticity #===========================================================# #———- plot heat map—————# # import in all fitness files
file_ls <- list.files(path = here("data/MC_partitioned/"), pattern = "*.csv", full.names = T)
name_ls <- list.files(path = here("data/MC_partitioned/"), pattern = "*.csv")
name_ls <- gsub("*.csv", "", name_ls)
# 60, which is about right
length(file_ls)
[1] 60
# read in files
fitness.ls <- lapply(file_ls, read.csv)
Warning: stack imbalance in 'lapply', 6 then 8
Warning: stack imbalance in '<-', 2 then 4
# assign unique ID
fitness.ls <- mapply(cbind, fitness.ls, "ID" = name_ls, SIMPLIFY = F)
process data
# get metainfo from ID
fitness.ls2 <- mclapply(fitness.ls, function(x){
id_col <- x$ID
# string split to extract all info
cue <- unlist(str_split(unique(id_col), pattern = "_"))[[3]]
log <- unlist(str_split(unique(id_col), pattern = "_"))[[4]]
rand_var <- unlist(str_split(unique(id_col), pattern = "_"))[[5]]
# get mean
mean_fitness <- mean(x$max_fitness)
# get sd
sd_fitness <- sd(x$max_fitness)
# bind results
res <- cbind(x, cue= cue, log = log, rand_var = rand_var, mean_fitness = mean_fitness, sd_fitness = sd_fitness)
return(res)
})
Get reference data
reference_ls <- list.files(path = here("data/MC2"), pattern = "*.csv", full.names = T)
reference_name.ls <- gsub("*.csv", "", list.files(path = here("data/MC2/"), pattern = "*.csv"))
# read in the files
reference.ls <- lapply(reference_ls, read.csv)
# assign unique ID
reference.ls <- mapply(cbind, reference.ls, "ID" = reference_name.ls, SIMPLIFY = F)
# get meta data
reference.ls2 <- mclapply(reference.ls, function(x){
id_col <- x$ID
# string split to extract all info
cue <- unlist(str_split(unique(id_col), pattern = "_"))[[2]]
# get log
third_col <- unlist(str_split(unique(id_col), pattern = "_"))[[3]]
log <- ifelse(third_col == "log", "log10", "none")
# get mean
mean_fitness <- mean(x$max_fitness)
# get sd
sd_fitness <- sd(x$max_fitness)
# bind results
res <- cbind(x, cue= cue, log = log, rand_var = "all", ref_mean_fitness = mean_fitness, ref_sd_fitness = sd_fitness)
return(res)
})
combine MC partitioned and reference df
# get unique column values for each cue, log, and rand_var combo
fitness.ls3 <- do.call(rbind, fitness.ls2)
fitness.ls3 <- fitness.ls3 %>% dplyr::distinct(ID, .keep_all = T)
# repeat with reference
reference.ls3 <- do.call(rbind, reference.ls2)
reference.ls3 <- reference.ls3 %>% dplyr::distinct(ID, .keep_all = T)
# combine!
ref_fit.df <- left_join(fitness.ls3, reference.ls3, by = c("cue" = "cue", "log"= "log"))
compute proportion fitness and variation
ref_fit.df2 <- ref_fit.df %>%
mutate(p_sd = sd_fitness/ref_sd_fitness,
p_mean = ref_mean_fitness/mean_fitness,
cue_log = paste0(cue, "_", log),
label = case_when(
cue == "G" ~ "Gametocyte",
cue == "I" ~ "Asexual iRBC",
cue == "I+Ig" ~ "Asexual&sexual\niRBC",
cue == "Ig" ~ "Sexual iRBC",
cue == "R" ~ "RBC"
),
parameter = case_when(
rand_var.x == "rho" ~ "ρ",
rand_var.x == "phin" ~ "ϕn",
rand_var.x == "phiw"~ "ϕw",
rand_var.x == "psin" ~ "ψn",
rand_var.x == "psiw" ~ "ψw",
rand_var.x == "beta" ~ "β"
))
plot!
# variation
mc_b <- ggplot() +
geom_tile(data = ref_fit.df2 , aes(x = label, y = parameter, fill = p_sd)) +
facet_wrap(~log) +
theme_bw() +
viridis::scale_fill_viridis() +
labs(x = "Cue", y = "Parameter randomized", fill = expression(frac(sd("1 parameter randomized"), sd("all parameters randomized")))) +
theme(legend.position="top",
axis.text.x = element_text(angle = 45, hjust=1))
# mean fitness
mc_c <- ggplot() +
geom_tile(data = ref_fit.df2 , aes(x = label, y = parameter, fill = p_mean)) +
facet_wrap(~log) +
theme_bw() +
viridis::scale_fill_viridis() +
labs(x = "Cue", y = "Parameter randomized", fill = expression(frac(Mean("all parameters randomized"), Mean("1 parameter randomized")))) +
theme(legend.position="top",
axis.text.x = element_text(angle = 45, hjust=1))
mc_partition <- ggarrange(mc_b, mc_c, ncol = 1)
#————– get violine plot of variation in fitness ——————–# # read MC data
# read in dymamics
mc_G_log.dyn <- read_parquet(here("data/MC2/mc_G_log_dyn.parquet"))
mc_G.dyn <- read_parquet(here("data/MC2/mc_G_dyn.parquet"))
mc_R_log.dyn <- read_parquet(here("data/MC2/mc_R_log_dyn.parquet"))
mc_R.dyn <- read_parquet(here("data/MC2/mc_R_dyn.parquet"))
mc_I_log.dyn <- read_parquet(here("data/MC2/mc_I_log_dyn.parquet"))
mc_I.dyn <- read_parquet(here("data/MC2/mc_I_dyn.parquet"))
mc_Ig_log.dyn <- read_parquet(here("data/MC2/mc_Ig_log_dyn.parquet"))
mc_Ig.dyn <- read_parquet(here("data/MC2/mc_Ig_dyn.parquet"))
mc_I_Ig_log.dyn <- read_parquet(here("data/MC2/mc_I+Ig_log_dyn.parquet"))
mc_I_Ig.dyn <- read_parquet(here("data/MC2/mc_I+Ig_dyn.parquet"))
# read in fitness
mc_G_log.fitness <- read.csv(here("data/MC2/mc_G_log_fitness.csv"))
mc_G.fitness <- read.csv(here("data/MC2/mc_G_fitness.csv"))
mc_R_log.fitness <- read.csv(here("data/MC2/mc_R_log_fitness.csv"))
mc_R.fitness <- read.csv(here("data/MC2/mc_R_fitness.csv"))
mc_I_log.fitness <- read.csv(here("data/MC2/mc_I_log_fitness.csv"))
mc_I.fitness <- read.csv(here("data/MC2/mc_I_fitness.csv"))
mc_Ig_log.fitness <- read.csv(here("data/MC2/mc_Ig_log_fitness.csv"))
mc_Ig.fitness <- read.csv(here("data/MC2/mc_Ig_fitness.csv"))
mc_I_Ig_log.fitness <- read.csv(here("data/MC2/mc_I+Ig_log_fitness.csv"))
mc_I_Ig.fitness <- read.csv(here("data/MC2/mc_I+Ig_fitness.csv"))
examine variation
# plot fitness vs iteration
fitness.df <- rbind(
cbind(mc_G_log.fitness, id = "Gametocyte\nlog10"),
cbind(mc_G.fitness, id = "Gametocyte"),
cbind(mc_R_log.fitness, id = "RBC log10"),
cbind(mc_R.fitness, id = "RBC"),
cbind(mc_I_log.fitness, id = "Asexual iRBC\nlog10"),
cbind(mc_I.fitness, id = "Asexual iRBC"),
cbind(mc_Ig_log.fitness, id = "Sexual iRBC\nlog10"),
cbind(mc_Ig.fitness, id = "Sexual iRBC"),
cbind(mc_I_Ig_log.fitness, id = "Asexual&sexual iRBC\nlog10"),
cbind(mc_I_Ig.fitness, id = "Asexual&sexual\niRBC")
)
# quantify variance and mean
fitness_var.df <- fitness.df %>%
dplyr::group_by(id) %>%
dplyr::summarise(median = median(max_fitness)) %>%
dplyr::mutate(id = forcats::fct_reorder(id, median))
plot violin with difference in deterministic model fitness and mean model fitness
# get deterministic df
det.df <- data.frame(fitness_var.df, `Maximum fitness` = c(8.49777, 9.494991,8.854682,9.573291,8.58856,9.561373,8.23991,8.181604,8.569285,9.618812)) %>%
dplyr::mutate(id = forcats::fct_reorder(id, median)) %>%
tidyr::pivot_longer(-id) %>%
mutate(classification = case_when(
name == "Maximum.fitness" ~"Optimal single infection",
name == "median" ~"Median Monte Carlo",
name == "mean" ~ "Mean Monte Carlo"))
mc_a <- ggplot() +
geom_point(data = det.df, aes(y = id, x = value, shape = classification, color = classification), size = 3, alpha = 0.8) +
geom_violin(data = fitness.df, aes(y = id, x = max_fitness), fill = "transparent") +
labs(x = "Fitness", y = "Cue", color = "Fitness", shape = "Fitness") +
theme_bw() +
theme(legend.position = "bottom") +
scale_color_manual(values=c("black", "#4575b4", "#fc8d59"))
#————– plot together———————–#
# arrange the heat map
ggarrange(mc_a, mc_partition, ncol = 2, nrow = 1, labels = c("A", "B"), align = "h")
Warning: Graphs cannot be horizontally aligned unless the axis parameter is set. Placing graphs unaligned.

#——————————————–# # dual cue optimization figure #——————————————–#
source(here("functions/chabaudi_si_clean_high.R"))
source(here("functions/chabaudi_si_clean.R"))
source(here("functions/par_to_hm_te.R"))
#———- plotting fitness of dual vs single cue opt ———# # import in previous data
# dual cue fitness
dual_fitness.df <- read.csv(here("data/dual_cue_opt4/dual_cue_fitness_20.csv"))
## make label and filter out very low fitness
dual_fitness.df <- dual_fitness.df %>%
mutate(temp_label = gsub("log", "log10", label),
temp_label_b = gsub("log", "log10", label_b),
label_final = paste0(temp_label, "+", temp_label_b)) %>%
filter(value > 2)
# get single cue fitness
si_dyn.df <- read_parquet(here("data/si_dyn/si_dyn_30.parquet"))
si_fitness.df <- si_dyn.df %>%
filter(variable == "tau_cum" & time == 20)
# join si and dual cue
dual_si_fitness.df <- dual_fitness.df %>%
left_join(select(si_fitness.df, id, si_fitness = value), by = "id") %>%
left_join(select(si_fitness.df, id_b = id, si_fitness_b = value), by = "id_b") %>%
mutate(si_fitness_max = ifelse(si_fitness > si_fitness_b, si_fitness, si_fitness_b),
dual_label = gsub("log", "log10", paste(label, "+", label_b)))
plot
dual_si_fitness.pl <- ggplot() +
geom_point(data = dual_si_fitness.df, aes(y = forcats::fct_reorder(dual_label, value), x = value, color = "Dual cue", shape = "Dual cue"), size = 3, alpha = 0.7) +
geom_point(data = dual_si_fitness.df, aes(y = forcats::fct_reorder(dual_label, value), x = si_fitness_max, color= "Best single cue", shape= "Best single cue"), size = 3, alpha = 0.7) +
labs(x = "Fitness", y = "Dual cue", color = "Cue", shape = "Cue") +
scale_color_manual(values=c("#fc8d59", "#4575b4")) +
geom_vline(xintercept = 9.883602) +
geom_text(aes(x=9.883602, label="\nTime-based fitness (df=9)", y = "G + R log10"), angle=90) +
xlim(8.35, 10) +
theme_bw() +
theme(legend.position = "top")
#———– time series conversion rate ————-# # dynamics simulation of high parameter cues (these serve as reference points)
# best dual cue combo
dual.cr <- chabaudi_si_clean(
parameters_cr = c(4.446192033, 10.97518275, 1.38762817, 23.3059254, -3.452052371, -18.0070692, 39.66614226, -3.545193141, 18.78350799),
immunity = "tsukushi",
parameters = parameters_tsukushi,
time_range = seq(0, 20, by = 1e-3),
cue_range = seq(6, 7, by = 1/500),
cue_range_b = seq(0, log10(6*(10^6)), by = (log10(6*(10^6)))/500),
cue = "R",
cue_b = "I",
log_cue = "log10",
log_cue_b = "log10",
solver = "vode",
dyn = T
)
*** recursive gc invocation
*** recursive gc invocation
*** recursive gc invocation
*** recursive gc invocation
*** recursive gc invocation
*** recursive gc invocation
*** recursive gc invocation
*** recursive gc invocation
*** recursive gc invocation
Warning in Predict.matrix.cr.smooth(object$margin[[i]], dat) :
passing an object of type 'language' to .C (arg 8) is deprecated
plot
dual_cr.pl <- ggplot() +
geom_line(data = dual_cr.df, aes(color = label_new, x = time, y = value), size = 1) +
geom_point(data = dual_cr.df %>% filter(time%%1 == 0), aes(color = label_new, x = time, y = value, shape = label_new), size = 3) +
labs(x = "Time (days)", y = "Conversion rate", color = "Cue", shape = "Cue") +
xlim(0, 20) +
scale_color_manual(values = c("#fc8d59","#fdcb44","black", "#4575b4")) +
theme_bw() +
theme(legend.position="right",
plot.margin = margin(t = 40, r = 0, b = 0, l = 0, unit = "pt")) +
guides(color = guide_legend(nrow = 4, byrow = TRUE))
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
ℹ Please use `linewidth` instead.
This warning is displayed once every 8 hours.
Call `lifecycle::last_lifecycle_warnings()` to see where this warning was generated.
#———— reaction norm heatmap of R log10 + I log10 ————# # process data
# make heatmap df
R_I.hm <- par_to_hm_te(par = c(4.446192033, 10.97518275, 1.38762817, 23.3059254, -3.452052371, -18.0070692, 39.66614226, -3.545193141, 18.78350799),
cue_range = seq(6, 7, length.out = 500),
cue_range_b = seq(0, 6.77815125, length.out = 500))
# process dynamics
R_I.dyn <- dual.cr %>%
tidyr::pivot_wider(names_from = variable, values_from = value) %>%
mutate(log_R = log10(R),
log_I = log10(I))
# examine sexual iRBC as well
R_Ig.dyn <- dual.cr %>%
tidyr::pivot_wider(names_from = variable, values_from = value) %>%
mutate(log_R = log10(R),
log_Ig = log10(Ig))
max(R_Ig.dyn$Ig)
[1] 175754.2
plot
dual_rn.pl <- ggplot() +
geom_raster(data = R_I.hm, aes(x = cue_range_b, y = cue_range, fill = cr)) +
scale_fill_viridis_c() +
geom_path(data = R_I.dyn, aes(x = log_I, y = log_R), color = "white", arrow = arrow(angle = 30, length = unit(0.1, "inches"))) +
geom_point(data = R_I.dyn %>% filter(row_number() %% 1000 == 1 & time <= 20), aes(x = log_I, y = log_R), color = "white") +
xlim(0.99*min(hablar::s(R_I.dyn$log_I), na.rm = T), 1.01* max(hablar::s(R_I.dyn$log_I), na.rm = T)) +
ylim(0.99*min(hablar::s(R_I.dyn$log_R), na.rm = T),1.01* max(hablar::s(R_I.dyn$log_R), na.rm = T)) +
labs(y = "RBC log10", x = "Asexual iRBC log10", fill = "Conversion\nrate") +
theme_dark() +
theme(legend.position = "right")
# just testing for sexual iRBC vs RBC
ggplot() +
geom_path(data = R_Ig.dyn, aes(x = Ig, y = log_R), color = "white", arrow = arrow(angle = 30, length = unit(0.1, "inches"))) +
geom_point(data = R_Ig.dyn %>% filter(row_number() %% 1000 == 1 & time <= 20), aes(x = Ig, y = log_R), color = "white") +
scale_x_continuous(trans = "log10") +
xlim(0, 200000) +
labs(y = "RBC log10", x = "Sexual iRBC log10", fill = "Conversion rate") +
theme_dark()
Scale for x is already present.
Adding another scale for x, which will replace the existing scale.

save figure for poster
dual_rn.pl2 <- ggplot() +
geom_raster(data = R_I.hm, aes(x = cue_range_b, y = cue_range, fill = cr)) +
scale_fill_viridis_c() +
geom_path(data = R_I.dyn, aes(x = log_I, y = log_R), color = "white", arrow = arrow(angle = 30, length = unit(0.1, "inches"))) +
geom_point(data = R_I.dyn %>% filter(row_number() %% 1000 == 1 & time <= 20), aes(x = log_I, y = log_R), color = "white") +
xlim(0.99*min(hablar::s(R_I.dyn$log_I), na.rm = T), 1.01* max(hablar::s(R_I.dyn$log_I), na.rm = T)) +
ylim(0.99*min(hablar::s(R_I.dyn$log_R), na.rm = T),1.01* max(hablar::s(R_I.dyn$log_R), na.rm = T)) +
labs(y = "RBC log10", x = "Asexual iRBC log10", fill = "Conversion rate") +
theme_dark() + theme(legend.position="top")
dual_cr.pl2 <- ggplot() +
geom_line(data = dual_cr.df, aes(color = label_new, x = time, y = value), size = 1) +
geom_point(data = dual_cr.df %>% filter(time%%1 == 0), aes(color = label_new, x = time, y = value, shape = label_new), size = 2) +
labs(x = "Time (days)", y = "Conversion rate", color = "Cue", shape = "Cue") +
xlim(0, 20) +
scale_color_manual(values = c("#4575b4", "#91bfdb","#fc8d59","#fdcb44")) +
theme_bw() +
theme(legend.position="top") +
guides(color = guide_legend(nrow = 2, byrow = TRUE))
ggarrange(dual_cr.pl2, dual_rn.pl2, align = "h", widths = c(1.25, 1))
ggsave(here("poster/dual_cue.png"), width = 7, height = 4)
#——– assemble final figure ————-#
# assemble panel B and C
dual_pl.BC <- ggarrange(dual_cr.pl, dual_rn.pl, align = "v", ncol = 1, labels = c("B", "C"))
Warning: Removed 3 rows containing missing values (`geom_line()`).
Warning: Removed 3 rows containing missing values (`geom_point()`).
Warning: Removed 219202 rows containing missing values (`geom_raster()`).
# assemble panel A
ggarrange(dual_si_fitness.pl, dual_pl.BC, ncol = 2, labels = c("A", ""), widths = c(1,1.1))
ggsave(here("figures/plos-bio/dual_cue.tiff"), units = "px", width = 2100, height = 1400, scale = 1.3, dpi=300, bg = "white")

#============================================# # dynamics of dual cue simulation (all combinations) #============================================# # conversion rate
ggsave(here("figures/plos-bio/dual_cue_cr.tiff"), units = "px", width = 2000, height = 1500, dpi=300, bg = "white")
Warning: Removed 26448 rows containing missing values (`geom_raster()`).
cumultative transmission transmission potential
Proving a point to myself
# it seems that R log+I log only inches ahead of other at the very end of the infection, suggesting that terminal investment is at play
ggplot(data = dual_tau.df_p, aes(x = time, y = value, color = label_plot)) +
geom_line() +
scale_fill_viridis_c() +
xlim(15, 20) +
ylim(5,10) +
labs(x = "Time (days)", y = "Dual cue combination", fill = "Conversion rate") +
theme_bw()
Warning: Removed 12500 rows containing missing values (`geom_line()`).

#============================================# # get dual cue disease map (simulated) #============================================# I am going to take the optimal dynamic (R log10 + I log10) and plot all possible disease curves and see if any follow the hysteresis curve. See below for real life disease curve.
plot
ggarrange(plotlist = dual_curve.pl, ncol = 2, nrow = 3, align = "hv")
Warning: Removed 1 row containing missing values (`geom_path()`).
Warning: Removed 1 rows containing missing values (`geom_point()`).
Warning: Removed 37 rows containing missing values (`geom_path()`).
Warning: Removed 4 rows containing missing values (`geom_point()`).
Warning: Removed 57 rows containing missing values (`geom_path()`).
Warning: Removed 6 rows containing missing values (`geom_point()`).
Warning: Removed 37 rows containing missing values (`geom_path()`).
Warning: Removed 4 rows containing missing values (`geom_point()`).
Warning: Removed 57 rows containing missing values (`geom_path()`).
Warning: Removed 6 rows containing missing values (`geom_point()`).
Warning: Removed 57 rows containing missing values (`geom_path()`).
Warning: Removed 6 rows containing missing values (`geom_point()`).
ggsave(here("figures/plos-bio/dual_curve1.tiff"), units = "px", width = 1000, height = 1000, scale = 1.5, dpi=300, bg = "white")

ggarrange(plotlist = dual_curve_xlog.pl, ncol = 2, nrow = 3, align = "hv")
Warning: Removed 1 row containing missing values (`geom_path()`).
Warning: Removed 1 rows containing missing values (`geom_point()`).
Warning: Removed 37 rows containing missing values (`geom_path()`).
Warning: Removed 4 rows containing missing values (`geom_point()`).
Warning: Removed 57 rows containing missing values (`geom_path()`).
Warning: Removed 6 rows containing missing values (`geom_point()`).
Warning: Removed 37 rows containing missing values (`geom_path()`).
Warning: Removed 4 rows containing missing values (`geom_point()`).
Warning: Removed 57 rows containing missing values (`geom_path()`).
Warning: Removed 6 rows containing missing values (`geom_point()`).
Warning: Removed 57 rows containing missing values (`geom_path()`).
Warning: Removed 6 rows containing missing values (`geom_point()`).
ggsave(here("figures/plos-bio/dual_curve2.tiff"), units = "px", width = 1000, height = 1000, scale = 1.5, dpi=300, bg = "white")

ggarrange(plotlist = dual_curve_ylog.pl, ncol = 2, nrow = 3, align = "hv")
Warning: Removed 1 row containing missing values (`geom_path()`).
Warning: Removed 1 rows containing missing values (`geom_point()`).
Warning: Removed 37 rows containing missing values (`geom_path()`).
Warning: Removed 4 rows containing missing values (`geom_point()`).
Warning: Removed 57 rows containing missing values (`geom_path()`).
Warning: Removed 6 rows containing missing values (`geom_point()`).
Warning: Removed 37 rows containing missing values (`geom_path()`).
Warning: Removed 4 rows containing missing values (`geom_point()`).
Warning: Removed 57 rows containing missing values (`geom_path()`).
Warning: Removed 6 rows containing missing values (`geom_point()`).
Warning: Removed 57 rows containing missing values (`geom_path()`).
Warning: Removed 6 rows containing missing values (`geom_point()`).
ggsave(here("figures/plos-bio/dual_curve3.tiff"), units = "px", width = 1000, height =1000, scale = 1.5, dpi=300, bg = "white")

ggarrange(plotlist = dual_curve_log.pl, ncol = 2, nrow = 3, align = "hv")
Warning: Removed 1 row containing missing values (`geom_path()`).
Warning: Removed 1 rows containing missing values (`geom_point()`).
Warning: Removed 37 rows containing missing values (`geom_path()`).
Warning: Removed 4 rows containing missing values (`geom_point()`).
Warning: Removed 57 rows containing missing values (`geom_path()`).
Warning: Removed 6 rows containing missing values (`geom_point()`).
Warning: Removed 37 rows containing missing values (`geom_path()`).
Warning: Removed 4 rows containing missing values (`geom_point()`).
Warning: Removed 57 rows containing missing values (`geom_path()`).
Warning: Removed 6 rows containing missing values (`geom_point()`).
Warning: Removed 57 rows containing missing values (`geom_path()`).
Warning: Removed 6 rows containing missing values (`geom_point()`).
ggsave(here("figures/plos-bio/dual_curve4.tiff"), units = "px", width = 1000, height = 1000, scale = 1.5, dpi=300, bg = "white")

#============================================# # real life disease curve #============================================# # execute code from report 10 to get final dataset The following graphs will be made: - R vs iRBC - R log10 vs iRBC - R vs iRBC log10 - R log10 vs iRBC log10
G vs iRBC
G log10 vs iRBC
G vs iRBC log10
G log10 vs iRBC log10
R vs G
R log10 vs G
R vs G log10
R log10 vs G log10
R on y-axis
r_i.dc <- ggplot(exp_ss.df) +
geom_point(aes(y = RBC, x = asex)) +
geom_path(aes(y = RBC, x = asex, colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
theme_bw() +
scale_color_viridis_c(limits = c(3, 21)) +
labs(x = "iRBC per µL", y = "RBC per µL", color = "Days\npost-infection") +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE))
rlog_i.dc <- ggplot(exp_ss.df) +
geom_point(aes(y = log10(RBC), x = asex)) +
geom_path(aes(y = log10(RBC), x = asex, colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
theme_bw() +
scale_color_viridis_c(limits = c(3, 21)) +
labs(x = "iRBC per µL", y = "log10(RBC) per µL", color = "Days\npost-infection") +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE))
r_ilog.dc <-ggplot(exp_ss.df) +
geom_point(aes(y = RBC, x = log10(asex))) +
geom_path(aes(y = RBC, x = log10(asex), colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
theme_bw() +
scale_color_viridis_c(limits = c(3, 21)) +
labs(x = "log10(iRBC) per µL", y = "RBC per µL", color = "Days\npost-infection") +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE))
rlog_ilog.dc <- ggplot(exp_ss.df) +
geom_point(aes(y = log10(RBC), x = log10(asex))) +
geom_path(aes(y = log10(RBC), x = log10(asex), colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
theme_bw() +
scale_color_viridis_c(limits = c(3, 21)) +
labs(x = "log10(iRBC) per µL", y = "log10(RBC) per µL", color = "Days\npost-infection") +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE))
G on y-axis
g_i.dc <- ggplot(exp_ss.df) +
geom_point(aes(y = gam, x = asex)) +
geom_path(aes(y = gam, x = asex, colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
theme_bw() +
scale_color_viridis_c(limits = c(3, 21)) +
labs(x = "iRBC per µL", y = "Gametocyte per µL", color = "Days\npost-infection") +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE))
glog_i.dc <- ggplot(exp_ss.df) +
geom_point(aes(y = log10(gam), x = asex)) +
geom_path(aes(y = log10(gam), x = asex, colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
theme_bw() +
scale_color_viridis_c(limits = c(3, 21)) +
labs(x = "iRBC per µL", y = "log10(Gametocyte) per µL", color = "Days\npost-infection") +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE))
g_ilog.dc <- ggplot(exp_ss.df) +
geom_point(aes(y = gam, x = log10(asex))) +
geom_path(aes(y = gam, x = log10(asex), colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
theme_bw() +
scale_color_viridis_c(limits = c(3, 21)) +
labs(x = "log10(iRBC) per µL", y = "Gametocyte per µL", color = "Days\npost-infection") +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE))
glog_ilog.dc <- ggplot(exp_ss.df) +
geom_point(aes(y = log10(gam), x = log10(asex))) +
geom_path(aes(y = log10(gam), x = log10(asex), colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
theme_bw() +
scale_color_viridis_c(limits = c(3, 21)) +
labs(x = "log10(iRBC) per µL", y = "log10(Gametocyte) per µL", color = "Days\npost-infection") +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE))
R vs G
r_g.dc <- ggplot(exp_ss.df) +
geom_point(aes(y = RBC, x = gam)) +
geom_path(aes(y = RBC, x = gam, colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
theme_bw() +
scale_color_viridis_c(limits = c(3, 21)) +
labs(x = "Gametocyte per µL", y = "RBC per µL", color = "Days\npost-infection") +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE))
rlog_g.dc <- ggplot(exp_ss.df) +
geom_point(aes(y = log10(RBC), x = gam)) +
geom_path(aes(y = log10(RBC), x = gam, colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
theme_bw() +
scale_color_viridis_c(limits = c(3, 21)) +
labs(x = "Gametocyte per µL", y = "log10(RBC per µL)", color = "Days\npost-infection") +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE))
r_glog.dc <- ggplot(exp_ss.df) +
geom_point(aes(y = RBC, x = log10(gam))) +
geom_path(aes(y = RBC, x = log10(gam), colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
theme_bw() +
scale_color_viridis_c(limits = c(3, 21)) +
labs(x = "log10(Gametocyte) per µL", y = "RBC per µL", color = "Days\npost-infection") +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE))
rlog_glog.dc <- ggplot(exp_ss.df) +
geom_point(aes(y = log10(RBC), x = log10(gam))) +
geom_path(aes(y = log10(RBC), x = log10(gam), colour = day, group = id), arrow = arrow(type = "closed", angle = 10, length = unit(0.2, "inches"))) +
theme_bw() +
scale_color_viridis_c(limits = c(3, 21)) +
labs(x = "log10(Gametocyte) per µL", y = "log10(RBC) per µL", color = "Days\npost-infection") +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE))
plot together


#===========================================# # static competition #===========================================# #——- heat map —————# # calculate fitness difference for 20 days
# get dynamics
static.ls <- list.files(path = here("data/ci_static/"), pattern = "*.parquet", full.names = T)
static.ls <- lapply(static.ls, read_parquet)
# get fitness at day 20 (optimized for 20 days)
static_fitness.ls <- mclapply(static.ls, function(x){
x %>% filter(time == 20 & variable %in% c("tau_cum1", "tau_cum2"))
})
static_fitness.df <- do.call(rbind, static_fitness.ls)
static_fitness.df <- tidyr::pivot_wider(static_fitness.df, names_from = "variable", id_cols = c("id_1", "id_2")) %>%
group_by(id_1, id_2) %>%
mutate(fitness_difference = tau_cum1-tau_cum2)
write.csv(static_fitness.df, here("data/ci_static.csv"))
import and process data
ez_label <- read.csv(here("data/ez_label.csv"))
ez_label <- read.csv(here("data/ez_label.csv"))
# join with labelling
static.df2 <- static.df %>%
left_join(select(ez_label, id_ci, label_ci_1 = label_ci), by = c("id_1" = "id_ci")) %>%
left_join(select(ez_label, id_ci, label_ci_2 = label_ci), by = c("id_2" = "id_ci")) %>%
select(label_ci_1, label_ci_2, fitness_difference) %>%
mutate(label_ci_1 = gsub("log", "log10", label_ci_1),
label_ci_2 = gsub("log", "log10", label_ci_2))
Error in left_join(., select(ez_label, id_ci, label_ci_1 = label_ci), :
object 'static.df' not found
plot
ggarrange(static.pl1, static.pl2, align = "hv", widths = c(1, 0.2))
Warning: Graphs cannot be vertically aligned unless the axis parameter is set. Placing graphs unaligned.

ggarrange(static.pl1, static.pl2, align = "hv", widths = c(1, 0.2))
Warning: Graphs cannot be vertically aligned unless the axis parameter is set. Placing graphs unaligned.
ggsave(here("figures/plos-bio/static_competition_a.tiff"), units = "px", width = 2250, height = 1500, scale = 1.2, dpi=300, bg = "white")

#—— effect cue perception ——-# ## logging
# get non-logged pairings
static_nolog <- static.df2 %>%
mutate(cue_1 = trimws(gsub("\\ .*", "", label_ci_1)),
log_1 = case_when(
str_detect(label_ci_1, "log") ~ "log",
str_detect(label_ci_1, "log", negate = T) ~ "none")) %>%
filter(log_1 == "none")
static_log <- static.df2 %>%
mutate(cue_1 = trimws(gsub("\\ .*", "", label_ci_1)),
log_1 = case_when(
str_detect(label_ci_1, "log") ~ "log",
str_detect(label_ci_1, "log", negate = T) ~ "none")) %>%
filter(log_1 == "log")
static_log.df <- left_join(
select(static_nolog, cue_1, label_ci_2, log_1, None = fitness_difference),
select(static_log, cue_1, label_ci_2, log_1, Log = fitness_difference),
by = c("cue_1", "label_ci_2")) %>%
filter(!is.na(None) & !is.na(Log)) %>%
mutate(classification = ifelse(Log > None, "Logged better", "Not logged better"))
combined
static_nocomb <- static.df2 %>%
mutate(cue_1 = ifelse(
str_detect(label_ci_1, "sum"), "I+Ig",
trimws(gsub("+1.*|\\ log", "", label_ci_1))
),
log_1 = case_when(
str_detect(label_ci_1, "log") ~ "log",
str_detect(label_ci_1, "log", negate = T) ~ "none"),
comb_1 = case_when(
str_detect(label_ci_1, "1+|sum") ~ "comb",
str_detect(label_ci_1, "1+|sum", negate = T) ~ "none"
)) %>%
filter(comb_1 == "none")
static_comb <- static.df2 %>%
mutate(cue_1 = ifelse(
str_detect(label_ci_1, "sum"), "I+Ig",
trimws(gsub("+1.*|\\ log", "", label_ci_1))
),
log_1 = case_when(
str_detect(label_ci_1, "log") ~ "log",
str_detect(label_ci_1, "log", negate = T) ~ "none"),
comb_1 = case_when(
str_detect(label_ci_1, "1+|sum") ~ "comb",
str_detect(label_ci_1, "1+|sum", negate = T) ~ "none"
)) %>%
filter(comb_1 == "comb")
static_comb.df <- left_join(
select(static_nocomb, cue_1, label_ci_2, log_1, Self = fitness_difference),
select(static_comb, cue_1, label_ci_2, log_1, Total = fitness_difference),
by = c("cue_1", "log_1", "label_ci_2")) %>%
filter(!is.na(Total) & !is.na(Self)) %>%
mutate(classification = ifelse(Total > Self, "Total better", "Self better"))
plot

ggarrange(static_log.pl, static_comb.pl, ncol = 1, nrow = 2, align = "v")
ggarrange(static_log.pl, static_comb.pl, ncol = 1, nrow = 2, align = "v")
ggsave(here("figures/plos-bio/static_competition_b.tiff"), units = "px", width = 1000, height = 2000, scale = 1.2, dpi=300, bg = "white")

#===========================================# static competition dynamics #===========================================# #———–G log10————#
# plot together
Glog_dyn.pl <- ggarrange(Glog_cr.pl, Glog_I.pl, Glog_G.pl, Glog_tau.pl, ncol = 1, align = "v")
Warning: Removed 272032 rows containing missing values (`geom_raster()`).
Warning: Removed 272032 rows containing missing values (`geom_raster()`).
Warning: Removed 272032 rows containing missing values (`geom_raster()`).
Warning: Removed 272032 rows containing missing values (`geom_raster()`).
#———–R as cue———–#
R_dyn.pl <- ggarrange(R_cr.pl, R_I.pl, R_R.pl, R_tau.pl, ncol = 1, align = "v")
Warning: Removed 238028 rows containing missing values (`geom_raster()`).
Warning: Removed 238028 rows containing missing values (`geom_raster()`).
Warning: Removed 238028 rows containing missing values (`geom_raster()`).
Warning: Removed 238028 rows containing missing values (`geom_raster()`).
plot together

#===========================================# # invasion analysis #===========================================# # import in data (already 20 days )
invade.df <- read.csv(here("data/ci_invasion.csv"))
process data for invasion matrix
invade.mat <- invade.df %>%
group_by(V1 = pmin(mut_id, res_id), V2 = pmax(mut_id, res_id)) %>% # group by cue competition, irregardless of order
mutate(id_alt = paste0(V1, V2),
invade = case_when(
fitness > 0 ~ "invade",
fitness < 0 ~ "not invade"
)) %>%
group_by(id_alt) %>%
mutate(
mut_is_V1 = case_when(
mut_id == V1 ~ "V1_invade",
mut_id != V1 ~ "V1_invaded")) %>%
arrange(id_alt) %>%
select(fitness, V1, V2, id_alt, invade, mut_is_V1) %>%
tidyr::pivot_wider(names_from = mut_is_V1, values_from = fitness) %>%
group_by(id_alt) %>%
mutate(V1_invade2 = gsub("NA", "", paste0(V1_invade, collapse = "")),
V1_invaded2 = gsub("NA", "", paste0(V1_invaded, collapse = ""))) %>%
distinct(id_alt, .keep_all = T) %>%
mutate(
category = case_when(
V1_invade2 > 0 & V1_invaded2 > 0 ~ "Mutual invasion",
V1_invade2 > 0 & V1_invaded2 < 0 ~ "Only strain 1 invasion",
V1_invade2 < 0 & V1_invaded2 > 0 ~ "Only strain 2 invasion",
V1_invade2 < 0 & V1_invaded2 < 0 ~ "Mutual non-invasion"
)) %>%
select(V1, V2, invasion = category)
invade.df %>% filter(mut_id == "G-i_none")
invade.df %>% filter(res_id == "G-i_none")
invade.mat4 <- rbind(
select(invade.mat3, V1_label, V2_label, invasion),
select(invade.mat3, V2_label = V1_label, V1_label = V2_label) %>% mutate(invasion = NA)) %>%
mutate(
invasion_2 = case_when(
invasion == "Mutual invasion" ~ "Mutual invasion",
invasion == "Only strain 1 invasion" ~ "Competitive exclusion\nof another cue",
invasion == "Only strain 2 invasion" ~ "Competitive exclusion\nby another cue"
)) %>%
filter(!is.na(V1_label))
Adding missing grouping variables: `id_alt`
Adding missing grouping variables: `id_alt`
plot invasion matrix

create summary bar chart
# create a stacked barchart for summary
## filter out na
invade.matalt <- invade.mat3 %>% na.exclude()
# get frquency from both sides. Note when grouping for V2, from the perspective of cue 2, scenarrio when strain 2 invade = strain 1 invade
invade.matalt1 <- invade.matalt %>% group_by(V1_label, invasion) %>%
summarize(frequency_1 = n())
invade.matalt2 <- invade.matalt %>%
mutate(invasion_alt = case_when(
invasion == "Only strain 1 invasion" ~ "Only strain 2 invasion",
invasion == "Only strain 2 invasion" ~ "Only strain 1 invasion",
invasion == "Mutual invasion" ~ "Mutual invasion",
invasion == "Mutual non-invasion" ~ "Mutual non-invasion"
)) %>%
group_by(V2_label, invasion_alt) %>%
summarize(frequency_2 = n())
# full join and sum. has confirmed all of them add up to 14
invade.matalt3 <- full_join(invade.matalt1, invade.matalt2, by = c("V1_label" = "V2_label", "invasion" = "invasion_alt"))
invade.matalt3[is.na(invade.matalt3)] <- 0
invade.matalt4 <- invade.matalt3 %>%
mutate(freq = frequency_1 + frequency_2) %>%
mutate(temp = case_when(
invasion == "Only strain 1 invasion" ~ freq
)) %>%
group_by(V1_label) %>%
mutate(invade_1_freq = max(temp, na.rm = T)) %>%
mutate(invasion_2 = case_when(
invasion == "Mutual invasion" ~ "Mutual invasion",
invasion == "Only strain 1 invasion" ~ "Competitive exclusion\nof another cue",
invasion == "Only strain 2 invasion" ~ "Competitive exclusion\nby another cue"
))

plot together


ggarrange(invasion.pl1, invasion.pl2, align = "h", common.legend = T, widths = c(2, 1))
ggarrange(invasion.pl1, invasion.pl2, align = "h", common.legend = T, widths = c(2, 1))
ggsave(here("figures/plos-bio/invasion_a.tiff"), units = "px", width = 2250, height = 1100, scale = 1.4, dpi=300, bg = "white")

#—————- invasion pairwise comparison—————–# ## proces data
combined
invade_nocomb <- invade.df2 %>%
mutate(cue_1 = ifelse(
str_detect(label_ci_1, "sum"), "I+Ig",
trimws(gsub("+1.*|\\ log", "", label_ci_1))
),
log_1 = case_when(
str_detect(label_ci_1, "log") ~ "log",
str_detect(label_ci_1, "log", negate = T) ~ "none"),
comb_1 = case_when(
str_detect(label_ci_1, "1+|sum") ~ "comb",
str_detect(label_ci_1, "1+|sum", negate = T) ~ "none"
)) %>%
filter(comb_1 == "none")
invade_comb <- invade.df2 %>%
mutate(cue_1 = ifelse(
str_detect(label_ci_1, "sum"), "I+Ig",
trimws(gsub("+1.*|\\ log", "", label_ci_1))
),
log_1 = case_when(
str_detect(label_ci_1, "log") ~ "log",
str_detect(label_ci_1, "log", negate = T) ~ "none"),
comb_1 = case_when(
str_detect(label_ci_1, "1+|sum") ~ "comb",
str_detect(label_ci_1, "1+|sum", negate = T) ~ "none"
)) %>%
filter(comb_1 == "comb")
invade_comb.df <- left_join(
select(invade_nocomb, cue_1, res_id, log_1, Self = fitness),
select(invade_comb, cue_1, res_id, log_1, Total = fitness),
by = c("cue_1", "log_1", "res_id")) %>%
filter(!is.na(Total) & !is.na(Self)) %>%
mutate(classification = ifelse(Total > Self, "Total better", "Self better"))
invade_comb.df
plot

ggarrange(invade_log.pl, invade_comb.pl, align = "h", ncol = 2)
ggarrange(invade_log.pl, invade_comb.pl, align = "h", ncol = 2)
ggsave(here("figures/plos-bio/invasion_b.tiff"), units = "px", width = 2250, height = 850, scale = 1.2, dpi=300, bg = "white")

#===========================================# # Cue performance across single, co-infection, static, and invasion #===========================================#
plot

#-=====================# # Partitioning best cue #=====================-# #——- single infection ———–# # redo some optimization (lower fitness in no R than default)
source(here("functions/chabaudi_si_clean_R.R"))
source(here("functions/chabaudi_si_clean_N.R"))
# I none
cl <- makeCluster(detectCores()); setDefaultCluster(cl = cl)
I_no_R <- optimParallel(
par = rep(0.5,4), # start at 0.5x4
fn = chabaudi_si_clean_R,
control = list(trace = 6, fnscale = -1),
immunity = "tsukushi",
parameters = parameters_tsukushi,
time_range = seq(0, 20, by = 1e-3),
cue_range = seq(0, 6*(10^6), by = (6*(10^6))/5000),
cue = "I",
log_cue = "none",
solver = "vode")
stopCluster(cl)
# 0.144021 -43.1046 2030.27 -524.686
# 8.69589
import and process data
# import in data
si_partition.ls <- list.files(path = here("data/partition/si/"), pattern = "*.csv", full.names = T)
si_partition.ls <- lapply(si_partition.ls, read.csv)
si_partition.df <- do.call(rbind, si_partition.ls)
# combine with si fitness (default)
si_partition.df <- si_partition.df %>% left_join(select(si_fitness.df, id, fitness = value), by = "id")
# make longer
si_partition.df2 <- tidyr::pivot_longer(si_partition.df, c(fitness_R, fitness_N, fitness_W, fitness))
# calculate coefficient of variation. Also rename
si_partition.df2 <- si_partition.df2 %>%
group_by(name) %>%
mutate(cv = sd(value)/mean(value)*100,
mean = mean(value),
category = case_when(
name == "fitness_R" ~ "No RBC limitation",
name == "fitness_W" ~ "No targeted immunity",
name == "fitness_N" ~ "No indiscriminate\nimmunity",
name == "fitness" ~ "Default"
))
plot
library(ungeviz)
# raw fitness
si_partition.pl1 <- ggplot() +
geom_vpline(data = si_partition.df2, aes(y = fct_reorder(category, mean), x = mean, group = category, color = category), show.legend = F, size = 1) +
geom_point(data = si_partition.df2, aes(y = fct_reorder(category, mean), x = value), size = 2, alpha = 0.7) +
geom_line(data = si_partition.df2, aes(y = fct_reorder(category, mean), x = value, group = id), alpha = 0.2) +
labs(x = "Fitness", y = "Conditions") +
theme_bw()
# coefficient of variation
si_partition.pl2 <- ggplot() +
geom_bar(data = si_partition.df2, aes(y = fct_reorder(category, mean), x = cv), stat = "identity") +
labs(x = "Coefficient of\nvariation (%)", y = "") +
theme_bw() +
theme(axis.title.y=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank())
si_partition.pl <- ggarrange(si_partition.pl1, si_partition.pl2, widths = c(1, 0.3), align = "h")
si_partition.pl
ggsave(here("figures/plos-bio/partition_fitness.tiff"), width = 7, height = 4)
#——- consequences of no targeted immunity ————# # get dynamics of no targeted immunity
get_dyn <- function(df){
source(here("functions/chabaudi_si_clean_W.R"))
id <- df$id
cue <- df$cue
log <- df$log
par <- c(df$var_W1, df$var_W2, df$var_W3, df$var_W4)
cue_range <- seq(df$low, df$high, by = df$by)
# get dynamics
dyn <- chabaudi_si_clean_W(
parameters_cr = par,
immunity = "tsukushi",
parameters = parameters_tsukushi,
time_range = seq(0, 20, by = 1e-3),
cue_range = cue_range,
cue = cue,
log_cue = log,
solver = "vode",
dyn = T
)
# combine
dyn2 <- cbind(dyn, id = id, cue = cue, log = log)
write_parquet(dyn2, paste0(here("data/partition/si_dyn/"), id, "_noW_dyn.parquet"))
}
get df to run
# join with cue_range
cue_range_si.df <- read.csv(here("data/cue_range_si.csv"))
si_partition.df3 <- si_partition.df %>% left_join(select(cue_range_si.df, low, high, by, id), "id")
# lapply loop
si_partition.ls <- split(si_partition.df3, seq(nrow(si_partition.df3)))
mclapply(si_partition.ls, get_dyn)
process dataframe
plot conversion rate
mechanism: targeted immunity led to lower parasite density in the initial stages, which prevents parasites from making the switch from no conversion rate to high conversion rate. When parsite density undergoes drastic increase at the beginning due to lower immunity, this presents a higher degree of signal that allows parasite to make the switch appropriately
partition_cr.pl <- ggplot() +
geom_line(data = no_W.cr, aes(x = time, y= value, color = "No targeted immunity")) +
geom_line(data = si_dyn.cr, aes(x = time, y= value, color = "Default")) +
facet_wrap(~ez_label_si, ncol = 5) +
xlim(0, 20) +
geom_vline(xintercept = 7) +
labs(x = "Time (days)", y = "Conversion rate", color = "Condition") +
theme_bw()
no_W.cr
#—– cue state ————–#
function to get cue states
# function to get cue states
get_cue_state <- function(df){
cue <- trimws(gsub("_log|_none", "", unique(df$id)))
if(cue != "I+Ig"){
df2 <- df %>% filter(variable == cue)
if(str_detect(unique(df$id), "log")){
df2 <- df2 %>%
mutate(value = log10(value))
}
}
if(cue == "I+Ig"){
df2 <- df %>% filter(variable %in% c("I", "Ig")) %>%
group_by(time) %>%
mutate(value = sum(value))
if(str_detect(unique(df$id), "log")){
df2 <- df2 %>%
mutate(value = log10(value))
}
}
df2$value[df2$value == -Inf] <- 0
write_parquet(df2, paste0(here("data/partition/si_default_state/"), unique(df$id), "_noW_state.parquet"))
}
run function
# split dynamics based on id
no_W.split <- split(no_W.df, no_W.df$id)
# run function
mclapply(no_W.split, get_cue_state)
# get dataframe
no_W.state <- list.files(here("data/partition/si_state/"), pattern = "*.parquet", full.names = T)
no_W.state <- lapply(no_W.state, read_parquet)
no_W.state <- do.call(rbind, no_W.state)
no_W.state$value[no_W.state$value < 0] <- 0
# get same for si infection
default.split <- split(si_dyn.df, si_dyn.df$id)
mclapply(default.split, get_cue_state)
default.state <- list.files(here("data/partition/si_default_state/"), pattern = "*.parquet", full.names = T)
default.state <- lapply(default.state, read_parquet)
default.state <- do.call(rbind, default.state)
default.state$value[default.state$value < 0] <- 0
# manually correct non-logging
I_Ig.corr <- no_W.state %>% filter(id == "I+Ig_log") %>%
mutate(value = log10(value))
I_Ig.corr$value[I_Ig.corr$value < 0] <- 0
no_W.state2 <- no_W.state %>% filter(id != "I+Ig_log")
no_W.state2 <- no_W.state2 %>% rbind(no_W.state2, I_Ig.corr)
plot
absence of targeted immunity led to drastic increase in parasite density in early phases of infection. This produces high signal intensity for parasite and host-based cues, especially non-logged ones, which allows for state differentation. While this can be viewed as a modelling artifiact, it should be noted that the logged cues seldom changed as these changes in early infection did little to alter the actual early signal intensity sensed by the parasite. In an environment where there is heterogeneity in host response, and thus, signal, logging allows for parasites to adapt optimal strategy whereas non-logged cues must contend with sensitivity to immunity.
# function to individually plot stuff
plot_state <- function(df1, df2){
# plot state dynamics
state_pl <- ggplot() +
geom_line(data = df1, aes(x = time, y = value, color = name, group = name)) +
facet_wrap(~ez_label_si, scales = "free") +
xlim(1,20) +
theme_bw() +
theme(legend.position="none") +
labs(x = "", y = "Cue") +
scale_y_continuous(labels = function(x) format(x, scientific = TRUE)) +
scale_color_manual(values =c("Default" = "#4575b4", "No targeted\nimmunity" = "#fc8d59"))
# plot conversion rate dynamics
cr_pl <- ggplot() +
geom_raster(data = df2, aes(x = time, y = name, fill = value)) +
xlim(1,20) +
theme_bw() +
labs(x = "Time (days)") +
theme(axis.title.y=element_blank(),
axis.ticks.y=element_blank(),
legend.position = "none") +
scale_fill_viridis_c(lim = c(0, 1))
# arrange
ggarrange(state_pl, cr_pl, ncol = 1, nrow = 2, align = "v", heights = c(1, 0.4))
ggsave(paste0(here("figures/plos-bio/partition/"), unique(df1$id), ".tiff"), width = 4.5, height = 3.5)
}
split
# combine state
noW_default.state <- left_join(
select(no_W.state2, time, `No targeted\nimmunity` = value, id, ez_label_si),
select(default.state %>% filter(time <= 20), time, `Default` = value, id, ez_label_si), by = c("time", "id", "ez_label_si"))
noW_default.state2 <- tidyr::pivot_longer(noW_default.state, c(`No targeted\nimmunity`, `Default`))
# combine conversion raster
noW_default.cr <- left_join(
select(no_W.cr, time, `No targeted\nimmunity` = value, id, ez_label_si),
select(si_dyn.cr %>% filter(time <= 20), time, `Default` = value, id, ez_label_si), by = c("time", "id", "ez_label_si"))
noW_default.cr2 <- tidyr::pivot_longer(noW_default.cr, c(`No targeted\nimmunity`, `Default`))
# split
noW_default_state.ls <- split(noW_default.state2, noW_default.state2$id)
noW_default_cr.ls <- split(noW_default.cr2, noW_default.cr2$id)
# run function
mapply(plot_state, noW_default_state.ls, noW_default_cr.ls)
#——– reaction norms of default vs optimized ————# # get reaction norm and rug data
source(here("functions/par_to_df.R"))
# Gametocyte
g_log.rn <- par_to_df(par = c(1.211521, -3.936778, -1.312944, -1.285713), cue_range = seq(0, log10(6*(10^4)), by = (log10(6*(10^4)))/5000))
g_log.rn2 <- par_to_df(par = c(1.393860539, -4.253007616, -0.313947029, -2.000857344), cue_range = seq(0, log10(6*(10^4)), by = (log10(6*(10^4)))/5000))
g.rn <- par_to_df(par = c(0.04061288, -9.31445958, 74.13015506, -431.5984364), cue_range = seq(0, 6*(10^4), by = (6*(10^4))/5000))
g.rn2 <- par_to_df(par = c(0.541729073, -3.904616443, 0.87487412, -0.694177021), cue_range = seq(0, 6*(10^4), by = (6*(10^4))/5000))
# I+Ig
I_Ig_log.rn <- par_to_df(par = c(3.594042, 4.157744, -13.530672, 2.599905), cue_range = seq(0, log10(6*(10^6)), by = (log10(6*(10^6)))/5000))
I_Ig_log.rn2 <- par_to_df(par = c(63.71893822, -87.77671601, -56.55475514, -66.02209549), cue_range = seq(0, log10(6*(10^6)), by = (log10(6*(10^6)))/5000))
I_Ig.rn <- par_to_df(par = c(0.3159297, -46.1104558, 1250.752908, -6.1982093), cue_range = seq(0, 6*(10^6), by = (6*(10^6))/5000))
I_Ig.rn2 <- par_to_df(par = c(0.731982784, -21.69799449, 149.7841876, 17.02551769), cue_range = seq(0, 6*(10^6), by = (6*(10^6))/5000))
# convert log to non-logged scale
g_log.rn$cue_range <- 10^(g_log.rn$cue_range)
g_log.rn2$cue_range <- 10^(g_log.rn2$cue_range)
I_Ig_log.rn$cue_range <- 10^(I_Ig_log.rn$cue_range)
I_Ig_log.rn2$cue_range <- 10^(I_Ig_log.rn2$cue_range)
# get rug
g_log.rug <- default.state %>%
filter(label_si == "G log") %>%
mutate(value = 10^value) %>%
select(label_si, value)
g_log.rug2 <- no_W.state %>%
filter(label_si == "G log") %>%
mutate(value = 10^value) %>%
filter(value <= 6*(10^4)) %>%
select(label_si, value)
I_Ig_log.rug <- default.state %>%
filter(label_si == "I+Ig log") %>%
select(label_si, value)
I_Ig_log.rug2 <- no_W.state %>%
filter(label_si == "I+Ig log") %>%
select(label_si, value)
g.rug <- default.state %>%
filter(label_si == "G") %>%
select(label_si, value)
g.rug2 <- no_W.state %>%
filter(label_si == "G" & value <= 6*(10^4)) %>%
select(label_si, value)
I_Ig.rug <- default.state %>%
filter(label_si == "I+Ig") %>%
select(label_si, value)
I_Ig.rug2 <- no_W.state %>%
filter(label_si == "I+Ig") %>%
select(label_si, value)
# get rug limits
rug_lim <- rbind(g_log.rug,
g_log.rug2,
I_Ig_log.rug,
I_Ig_log.rug2,
g.rug,
g.rug2,
I_Ig.rug,
I_Ig.rug2) %>%
group_by(label_si) %>%
summarize(max = max(hablar::s(value), na.rm = T),
min = min(hablar::s(value), na.rm = T))
# combine and filter
rn <- rbind(
cbind(g_log.rn, label_si = "G log", condition = "Default"),
cbind(g_log.rn2, label_si = "G log", condition = "No targeted\nimmunity"),
cbind(g.rn, label_si = "G", condition = "Default"),
cbind(g.rn2, label_si = "G", condition = "No targeted\nimmunity"),
cbind(I_Ig_log.rn, label_si = "I+Ig log", condition = "Default"),
cbind(I_Ig_log.rn2, label_si = "I+Ig log", condition = "No targeted\nimmunity"),
cbind(I_Ig.rn, label_si = "I+Ig", condition = "Default"),
cbind(I_Ig.rn2, label_si = "I+Ig", condition = "No targeted\nimmunity")
) %>%
left_join(rug_lim, by = "label_si") %>%
group_by(label_si) %>%
filter(cue_range <= max & cue_range >= min)
# combine rug
rug <- rbind(cbind(g_log.rug, condition = "Default"),
cbind(g_log.rug2, condition = "No targeted\nimmunity"),
cbind(g.rug, condition = "Default"),
cbind(g.rug2, condition = "No targeted\nimmunity"),
cbind(I_Ig_log.rug, condition = "Default"),
cbind(I_Ig_log.rug2, condition = "No targeted\nimmunity"),
cbind(I_Ig.rug, condition = "Default"),
cbind(I_Ig.rug2, condition = "No targeted\nimmunity"))
# cobine with ezlabel
rn2 <- rn %>% left_join(ez_label, by = "label_si")
rug2 <- rug %>% left_join(ez_label, by = "label_si")
# filter rug
default.rug <- rug2 %>% filter(condition == "Default")
no.rug <- rug2 %>% filter(condition == "No targeted\nimmunity")
plot
ggplot() +
geom_line(data = rn2, aes(x = cue_range, y = cr, color = condition)) +
geom_rug(data = default.rug, aes(x = value, color = condition), sides = "b") +
geom_rug(data = no.rug, aes(x = value, color = condition), sides = "t") +
facet_wrap(~fct_relevel(ez_label_si, c("Gametocyte log10", "Gametocyte", "Asexual&sexual\niRBC log10", "Asexual&sexual iRBC")), scales = "free_x") +
scale_x_continuous(labels = function(x) format(x, scientific = TRUE)) +
theme_bw() +
scale_color_manual(values =c("Default" = "#4575b4", "No targeted\nimmunity" = "#fc8d59")) +
ylim(0, 1.1) +
labs(x = "Cue range", y = "Conversion rate", color = "Condition")
ggsave(here("figures/plos-bio/partition_rn.tiff"), width = 7.5, height = 6)
get conversion rate legend
noW_default.cr %>% filter(id == "G_log") %>%
ggplot() +
geom_raster(aes(x = time, y = id, fill = Default)) +
xlim(1,20) +
theme_bw() +
labs(x = "Time (days)",
fill = "Conversion rate") +
theme(axis.title.y=element_blank(),
axis.ticks.y=element_blank(),) +
scale_fill_viridis_c(lim = c(0, 1))
ggsave(here("figures/plos-bio/cr_legend.tiff"))
#================================# # Disease curves for single, co-infection, and invasion #===============================# # get data for disease curves
# single infection dynamics
si_dyn.df <- read_parquet(here("data/si_dyn/si_dyn_30.parquet"))
# co-infection dynamics (mon-cue)
ci_dyn.df <- read_parquet(here("data/ci_dyn/ci_dyn.parquet"))
# dual cue dynamics
dual_dyn.df <- read_parquet(here("data/dual_cue_dyn/dual_cue_dyn.parquet"))
#——- single cue comparison —————# # process data
#——— dual cue ————————–# # process data
# turn skinny
dual_dc.df <- dual_dyn.df %>%
mutate(label_alt = paste(label, "+" , label_b)) %>%
select(label_alt, time, variable, value) %>%
filter(variable == "I" | variable == "Ig" | variable == "R") %>%
distinct(label_alt, time, variable, .keep_all = T)
dual_dyn.df
dual_dc.df2 <- dual_dc.df %>%
tidyr::pivot_wider(names_from = variable, values_from = value, id_cols = c(time, label_alt)) %>%
mutate(total = I+Ig)
#write_parquet(dual_dc.df2, here("data/disease_curve/dual_dc.parquet"))
# good dual cue -> list of good performing dual cues that encompass wide variety of cues
selected_dual_cue <- c("R log + I log", "R + Ig log", "G log + I log", "G log + Ig log", "Ig + I log")
bad_dual_cue <- c("G + I", "R + Ig", "R log + Ig", "G + R", "G + R log", "G + Ig", "Ig + I", "R + I", "R log + I")
# get classification -> R log10 + I log10 as the only good one
dual_dc.high <- dual_dc.df2 %>% filter(label_alt %in% selected_dual_cue) %>%
mutate(label_alt = gsub("log", "log10", label_alt))
dual_dc.poor <- dual_dc.df2 %>% filter(label_alt %in% bad_dual_cue) %>%
mutate(label_alt = gsub("log", "log10", label_alt))
#write_parquet(dual_dc.high, here("data/disease_curve/dual_dc_high.parquet"))
#write_parquet(dual_dc.poor, here("data/disease_curve/dual_dc_poor.parquet"))
#——- plotting single and dual cue disease map together——-# # plot

#———- co-infection monocue ————-# Note that we are plotting only single strain to show that on a single strain level, co-infection leads to larger area than single infection! # process data
# join high performing with label
ci_dc.high2 <- ci_dc.high %>% left_join(ez_label, by = c("label" = "label_ci"))
Error in is.data.frame(y) : object 'ez_label' not found
loop to get area: single infection
# split df
si_dc.ls <- split(si_dc.df, si_dc.df$id)
# get area
si_dc.area <- cbind.data.frame(area = as.numeric(lapply(si_dc.ls, cha)), id_alt = names(lapply(si_dc.ls, cha)))
# join with fitness
si_fitness.df2 <- si_fitness.df %>%
select(id, fitness = value) %>%
distinct(id, fitness) %>%
left_join(ez_label, by = c("id" = "id_si"))
si_dc.area <- si_dc.area %>%
left_join(si_fitness.df2, by = c("id_alt" = "id"))
dual cue
# split
dual.dc <- read_parquet(here("data/disease_curve/dual_dc.parquet"))
# get area
dual_dc.area <- cbind.data.frame(area = as.numeric(lapply(dual_dc.ls, cha)), id_alt = names(lapply(dual_dc.ls, cha)))
# get R log+I log area: 293632850541
dual_dc.area %>% filter(id_alt == "R log + I log")
coinfection
# split
ci_dc.ls <- split(ci_dc.df, ci_dc.df$label)
# run function to find area
ci_dc.area <- cbind.data.frame(area = as.numeric(lapply(ci_dc.ls, cha)), id_alt = names(lapply(ci_dc.ls, cha)))
# join with fitness
ci_dc.area <- ci_dc.area %>%
left_join(select(ci_fitness.df, label, fitness = value), by = c("id_alt" = "label"))
ci_dc.area
#—— get fitted scatter plot for all single infection, co infection, and dual cue ——–#
"Area", y = "Fitness") +
Error: unexpected ',' in " "Area","
#——- plot together with disease curve ——–#
# single infection
si_vir.pl <- ggarrange(si_dc.pl, si_area.pl, align = "v", widths = c(1, 0.5))
# co-infection
ci_vir.pl <- ggarrange(ci_dc.pl, ci_area.pl, align = "v", widths = c(1, 0.5))
# single infection
si_vir.pl <- ggarrange(si_dc.pl, si_area.pl, align = "v", widths = c(1, 0.5))
# co-infection
ci_vir.pl <- ggarrange(ci_dc.pl, ci_area.pl, align = "v", widths = c(1, 0.5))
#——— static area comparison ————-# # compute area
# import in dc dynamic and fitness
static_dc.df <- read_parquet(here("data/disease_curve/static_dc.parquet"))
static_fitness.df <- read.csv(here("data/ci_static.csv"))
# get winner and loser
static_dc.df4 <- static_dc.df %>%
left_join(select(static_fitness.df, id_1, id_2, fitness_difference), by = c("id_1", "id_2")) %>%
filter(id_1 != id_2) %>%
mutate(
total_winner = case_when(
fitness_difference > 0 ~ total1,
fitness_difference< 0 ~ total2
),
total_loser = case_when(
fitness_difference > 0 ~ total2,
fitness_difference< 0 ~ total1
))%>%
filter(abs(fitness_difference) > 0.1)
# split by winner and loser
static_dc.ls1 <- split(select(static_dc.df4, R, total = total_winner), static_dc.df4$id_alt)
static_dc.ls2 <- split(select(static_dc.df4, R, total = total_loser), static_dc.df4$id_alt)
# get area
static_win.area <- cbind.data.frame(area = as.numeric(lapply(static_dc.ls1, cha)), status = "Winner")
static_loser.area <- cbind.data.frame(area = as.numeric(lapply(static_dc.ls2, cha)), status = "Loser")
# pair
static.area <- cbind(select(static_win.area, Winner = area),
select(static_loser.area, Loser = area)) %>%
mutate(classification = ifelse(Winner>Loser, "Winner larger area", "Loser larger area"))
static.area
plot static
static.area
static_area.pl <- ggpaired(static.area, cond1 = "Winner", cond2 = "Loser", line.color = "classification", alpha = 0.2) +
labs(x = "Status", y = "Area", color = "Comparison\n(Static)") +
scale_color_manual(values = c("Loser larger area" = "#fc8d59", "Winner larger area" = "#4575b4")) +
stat_compare_means(paired = TRUE, hjust = 0) +
guides(color=guide_legend(nrow=2,byrow=TRUE))
#——— invasion area comparison —————–# # get area
# import in dc dynamic and fitness
invasion_dc.df <- read_parquet(here("data/disease_curve/invasion_dc.parquet"))
invasion_fitness.df <- read.csv(here("data/ci_invasion.csv"))
# calculate area
invasion_dc.df4 <- invasion_dc.df %>%
left_join(invasion_fitness.df, by = c("mut_id", "res_id")) %>%
mutate(
total_winner = case_when(
fitness> 0 ~ total1,
fitness< 0 ~ total2
),
total_loser = case_when(
fitness > 0 ~ total2,
fitness < 0 ~ total1
)) %>%
filter(abs(fitness) > 0.1)
invasion_dc.df4 %>% distinct(id_alt)
# split by winner and loser
invasion_dc.ls1 <- split(select(invasion_dc.df4, R, total = total_winner), invasion_dc.df4$id_alt)
invasion_dc.ls2 <- split(select(invasion_dc.df4, R, total = total_loser), invasion_dc.df4$id_alt)
# get area
invasion_win.area <- cbind.data.frame(area = as.numeric(lapply(invasion_dc.ls1, cha)), status = "Winner")
invasion_loser.area <- cbind.data.frame(area = as.numeric(lapply(invasion_dc.ls2, cha)), status = "Loser")
# pair
invasion.area <- cbind(select(invasion_win.area, Winner = area),
select(invasion_loser.area, Loser = area)) %>%
mutate(classification = ifelse(Winner>Loser, "Winner larger area", "Loser larger area"))
invasion.area
plot
#—— plot together ————-#

#====================================# # dual cue dynamics figure #===================================#
get dual dynamics
dual.dyn <- chabaudi_si_clean(
parameters_cr = c(4.446192033, 10.97518275, 1.38762817, 23.3059254, -3.452052371, -18.0070692, 39.66614226, -3.545193141, 18.78350799),
immunity = "tsukushi",
parameters = parameters_tsukushi,
time_range = seq(0, 30, by = 1e-3),
cue_range = seq(6, 7, by = 1/500),
cue_range_b = seq(0, log10(6*(10^6)), by = (log10(6*(10^6)))/500),
cue = "R",
cue_b = "I",
log_cue = "log10",
log_cue_b = "log10",
solver = "vode",
dyn = T
)
# filter out relevent dataframes
dual.dyn_f <- dual.dyn %>%
filter(variable %in% c("I", "Ig", "G", "R", "N", "W"))
# cr only
dual.dyn_cr <- dual.dyn %>% filter(variable == "cr")
plot
dual_I.plt <- ggplot() +
geom_line(data = dual.dyn_f %>% filter(variable == "I"), aes(x = time, y = value/(10^5)),
color = "#4575b4") +
geom_point(data = dual.dyn_f %>% filter(variable == "I" & row_number() %% 1000 == 0),
aes(x = time, y = value/(10^5)), size = 2, color = "#4575b4") +
geom_line(data = dual.dyn_cr, aes(x = time, y = value)) +
scale_y_continuous(name = "Conversion rate",
sec.axis = sec_axis(~.*10^5, name="Asexual iRBC per µL")) +
labs(x = "Time (days)") +
xlim(0, 20) +
theme_bw() +
theme(legend.position = "none")
dual_Ig.plt <-ggplot() +
geom_line(data = dual.dyn_f %>% filter(variable == "Ig"), aes(x = time, y = value/(10^5)),
color = "#4575b4") +
geom_point(data = dual.dyn_f %>% filter(variable == "Ig" & row_number() %% 1000 == 0),
aes(x = time, y = value/(10^5)), size = 2, color = "#4575b4") +
geom_line(data = dual.dyn_cr, aes(x = time, y = value)) +
scale_y_continuous(name = "Conversion rate",
sec.axis = sec_axis(~.*10^5, name="Sexual iRBC per µL")) +
labs(x = "Time (days)") +
xlim(0, 20) +
theme_bw() +
theme(legend.position = "none")
dual_G.plt <-ggplot() +
geom_line(data = dual.dyn_f %>% filter(variable == "G"), aes(x = time, y = value/(10^4)),
color = "#4575b4") +
geom_point(data = dual.dyn_f %>% filter(variable == "G" & row_number() %% 1000 == 0),
aes(x = time, y = value/(10^4)), size = 2, color = "#4575b4") +
geom_line(data = dual.dyn_cr, aes(x = time, y = value)) +
scale_y_continuous(name = "Conversion rate",
sec.axis = sec_axis(~.*10^4, name="Gametocyte per µL")) +
labs(x = "Time (days)") +
xlim(0, 20) +
theme_bw() +
theme(legend.position = "none")
dual_R.plt <-ggplot() +
geom_line(data = dual.dyn_f %>% filter(variable == "R"), aes(x = time, y = value/(10^7)),
color = "#4575b4") +
geom_point(data = dual.dyn_f %>% filter(variable == "R" & row_number() %% 1000 == 0),
aes(x = time, y = value/(10^7)), size = 2, color = "#4575b4") +
geom_line(data = dual.dyn_cr, aes(x = time, y = value)) +
scale_y_continuous(name = "Conversion rate",
sec.axis = sec_axis(~.*10^7, name="RBC per µL")) +
labs(x = "Time (days)") +
xlim(0, 20) +
theme_bw() +
theme(legend.position = "none")
dual_N.plt <-ggplot() +
geom_line(data = dual.dyn_f %>% filter(variable == "N"), aes(x = time, y = value*10),
color = "#4575b4") +
geom_point(data = dual.dyn_f %>% filter(variable == "N" & row_number() %% 1000 == 0),
aes(x = time, y = value*10), size = 2, color = "#4575b4") +
geom_line(data = dual.dyn_cr, aes(x = time, y = value)) +
scale_y_continuous(name = "Conversion rate",
sec.axis = sec_axis(~.*0.1, name="Indiscriminate immunity")) +
labs(x = "Time (days)") +
xlim(0, 20) +
theme_bw() +
theme(legend.position = "none")
dual_W.plt <-ggplot() +
geom_line(data = dual.dyn_f %>% filter(variable == "W"), aes(x = time, y = value*2),
color = "#4575b4") +
geom_point(data = dual.dyn_f %>% filter(variable == "W" & row_number() %% 1000 == 0),
aes(x = time, y = value*2), size = 2, color = "#4575b4") +
geom_line(data = dual.dyn_cr, aes(x = time, y = value)) +
scale_y_continuous(name = "Conversion rate",
sec.axis = sec_axis(~.*0.5, name="Targeted immunity")) +
labs(x = "Time (days)") +
xlim(0, 20) +
theme_bw() +
theme(legend.position = "none")
plot together
ggarrange(dual_I.plt, dual_Ig.plt, dual_G.plt, dual_R.plt, dual_N.plt, dual_W.plt, nrow = 3, ncol = 2, align = "hv", labels = c("A", "B", "C", "D", "E", "F"))
ggsave(here("figures/plos-bio/dual_dyn.tiff"), units = "px", width = 2250, height = 2000, scale = 1, dpi=300, bg = "white")
#======================================# # Single and co-infection verification #======================================# # single infection
# import in all single infection data
si_val.ls <- list.files(path = here("data/si_validation"), pattern = "*.csv", full.names = T)
si_val.df <- lapply(si_val.ls, read.csv)
si_val.df <- do.call(rbind, si_val.df)
# get max fitness from simulation. left join with si_opt
si_opt.df <- read.csv(here("data/si_opt.csv"))
# we can see that all of the randomly simulated models have a fitness value that is less than the optimized model
si_val.df2 <- select(si_val.df, V1, id) %>%
left_join(si_opt.df, by =c("id" = "id")) %>%
mutate(fitness_difference = fitness_20 - V1) %>%
left_join(select(ez_label, id_si, ez_label_si), by = c("id" = "id_si"))
Model validation
# read in the results file
ci_val.ls <- list.files(path = here("data/ci_validation"), pattern = "*.csv", full.names = T)
ci_val.ls2 <- lapply(ci_val.ls, read.csv)
ci_val.df <- do.call(rbind, ci_val.ls2)
ci_val.df2
ci_val.df2 <- ci_val.df %>%
left_join(select(ez_label, label_ci, ez_label), by = c("label" = "label_ci"))
plot
si_val.plt <- ggplot(data = si_val.df2, aes(x = fitness_difference)) +
geom_histogram(bins = 50) +
geom_vline(xintercept = 0, color = "#fc8d59") +
facet_wrap(~ez_label_si, scales = "free", ncol = 3) +
labs(x = "Optimized fitness - random fitness", y = "Frequency") +
theme_bw()
ci_val.plt <- ggplot(data = ci_val.df2, aes(x = V1)) +
geom_histogram(bins = 50) +
geom_vline(xintercept = 0, color = "#fc8d59") +
facet_wrap(~ez_label, scales = "free", ncol = 4) +
labs(x = "Fitness difference between\noptimized and random strain", y = "Frequency") +
theme_bw()
ggarrange(si_val.plt, ci_val.plt, align = "hv", labels = c("A", "B"), widths = c(3,4))
ggsave(here("figures/plos-bio/validation.tiff"), units = "px", width = 2250, height = 1300, scale = 1.6, dpi=300, bg = "white")
#=========================# # Monte carlo dynamics supplementary #=========================# # run code in report 16

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQpgYGB7cn0KbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGZvcmNhdHMpCmxpYnJhcnkoaGVyZSkKbGlicmFyeShkZVNvbHZlKQpsaWJyYXJ5KGNyb25lKQpsaWJyYXJ5KG9wdGltUGFyYWxsZWwpCmxpYnJhcnkoZG9QYXJhbGxlbCkKbGlicmFyeShkb1JORykKbGlicmFyeShhcnJvdykKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KHBhcmFsbGVsKQpsaWJyYXJ5KGdncHVicikKbGlicmFyeShzY2FsZXMpCmBgYAoKTm90ZWJvb2sgZm9yIHBsb3R0aW5nIGFsbCBvZiB0aGUgZmlndXJlcyBmb3IgUGxvUyBCaW9sb2d5IG1hbnVzY3JpcHQgc3VibWlzc2lvbgoKR3VpZGVsaW5lczogdGFrZW4gZnJvbSBodHRwczovL2pvdXJuYWxzLnBsb3Mub3JnL3Bsb3NiaW9sb2d5L3MvZmlndXJlcyNsb2MtZmlndXJlLWZpbGUtcmVxdWlyZW1lbnRzCjEuIGZvcm1hdDogZXBzCjIuIG1heCBmaWxlIHNpemU6IDEwIE1CCjMuIHRleHQgc2l6ZTogQXJpYWwsIFRpbWVzLCBvciBTeW1ib2wgZm9udCBvbmx5IGluIDgtMTIgcG9pbnQKMi4gZmlndXJlIHNpemU6IFdpZHRoOiA3ODkg4oCTIDIyNTAgcGl4ZWxzIChhdCAzMDAgZHBpKS4gSGVpZ2h0IG1heGltdW06IDI2MjUgcGl4ZWxzIChhdCAzMDAgZHBpKS4KCgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCmZpZ3VyZSAxOiBiZXN0IHNpbmdsZSBhbmQgY28taW5mZWN0aW9uIGN1ZQojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCkZpZ3VyZSBkaXNwbGF5aW5nIHRoZSByZWFjdGlvbiBub3JtcyBvZiBiZXN0IHNpbmdsZSBhbmQgY28taW5mZWN0aW9uLgoKIy0tLS0tLS0gb3B0aW1hbCBjdWUgcmVhY3Rpb24gbm9ybSAtLS0tLS0tLS0tLSMKIyByZWFkIGRhdGEKYGBge3J9CiMgc2luZ2xlIGluZmVjdGlvbiBkeW5hbWljcywgcmVhY3Rpb24gbm9ybXMsIGFuZCBydWdzCnNpX2R5bi5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9zaV9keW4vc2lfZHluXzMwLnBhcnF1ZXQiKSkgCnNpX3JuLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL3NpX2R5bi9zaV9ybi5wYXJxdWV0IikpCnNpX3J1Zy5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9zaV9keW4vc2lfcnVnLnBhcnF1ZXQiKSkgJT4lIAogIGRpc3RpbmN0KHZhbHVlLCBsYWJlbCwgLmtlZXBfYWxsID0gVCkKCiMgY28taW5mZWN0aW9uIGR5bmFtaWNzLCByZWFjdGlvbiBub3JtcywgYW5kIHJ1Z3MKY2lfZHluLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2NpX2R5bi9jaV9keW4ucGFycXVldCIpKQpjaV9ybi5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9jaV9keW4vY2lfcm4ucGFycXVldCIpKQpjaV9ydWcuZGYgPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvY2lfZHluL2NpX3J1Zy5wYXJxdWV0IikpICU+JSAKICBkaXN0aW5jdCh2YWx1ZSwgbGFiZWwsIC5rZWVwX2FsbCA9IFQpCgpjaV9ydWcuZGYKYGBgCgojIHByb2Nlc3MgZGF0YSBmb3IgcmVhY3Rpb24gbm9ybQpgYGB7cn0KIyBpbXBvcnQgbGFiZWxsaW5nIHNjaGVtZQplel9sYWJlbCA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2V6X2xhYmVsLmNzdiIpKQoKIyBnZXQgc2lfbGFiZWwgd2l0aCBjaSBjdWUgcmFuZ2UKc2lfY2lfcnVnLmRmIDwtIGNpX3J1Zy5kZiAlPiUgCiAgbXV0YXRlKGxhYmVsX3NpID0gY2FzZV93aGVuKAogICAgbGFiZWwgJWluJSBjKCJJIiwgIkkxK0kyIikgfiAiSSIsCiAgICBsYWJlbCAlaW4lIGMoIkkgbG9nIiwiSTErSTIgbG9nIikgfiAiSSBsb2ciLAogICAgbGFiZWwgJWluJSBjKCJJZyIsICJJZzErSWcyIikgfiAiSWciLAogICAgbGFiZWwgJWluJSBjKCJJZyBsb2ciKSB+ICJJZyBsb2ciLAogICAgbGFiZWwgJWluJSBjKCJzdW0iLCAiSStJZyIpIH4gIkkrSWciLAogICAgbGFiZWwgJWluJSBjKCJzdW0gbG9nIiwgIkkrSWcgbG9nIikgfiAiSStJZyBsb2ciLAogICAgbGFiZWwgPT0gIlIiIH4gIlIiLAogICAgbGFiZWwgPT0gIlIgbG9nIiB+ICJSIGxvZyIsCiAgICBsYWJlbCAlaW4lIGMoIkciLCAiRzErRzIiKSB+ICJHIiwKICAgIGxhYmVsID09ICJHIGxvZyIgfiAiRyBsb2ciCiAgKSkgCgojIGdldCBsaW1pdCBmb3Igc2lfcnVnCnNpX3J1Z19saW0uZGYgPC0gc2lfcnVnLmRmICU+JSAKICBmaWx0ZXIodGltZSA8PSAyMCkgJT4lCiAgZ3JvdXBfYnkobGFiZWwpJT4lIAogIHN1bW1hcmlzZShtaW4gPSBtaW4odmFsdWUsIG5hLnJtID0gVCkqMC45LAogICAgICAgICBtYXggPSBtYXgodmFsdWUsIG5hLnJtID0gVCkqMS4xKSAlPiUgCiAgc2VsZWN0KGxhYmVsX3NpID0gbGFiZWwsIG1pbl9zaSA9IG1pbiwgbWF4X3NpID0gbWF4KQoKIyBmaWx0ZXIgdG8gcmVzdHJpY3Rpb24gY29udmVyc2lvbiByYXRlIHJlYWN0aW9uIG5vcm0gcmFuZ2UgdG8gY3VlIHJhbmdlcyB0aGF0IGFwcGVhciBpbiBydWcKIyMgY2hhbmdlIHRvIEluZi8taW5mIHRvIE5BLiBOb3RlIHRoYXQgSSBhbSBmaXJzdCBqb2luaW5nIHdpdGggc2kgcnVnIGxpbSB0byBjaGVjayB3aGljaCBsaW1pdCBpcyBsYXJnZXIsIFdlIHdpbGwgZ28gd2l0aCB0aGUgY3VlIHJhbmdlIHRoYXQgaGFzIHRoZSBsYXJnZXN0IHNwYW4KY2lfcnVnX2xpbS5kZiA8LSBzaV9jaV9ydWcuZGYgJT4lIAogIGdyb3VwX2J5KGxhYmVsKSAlPiUgCiAgbXV0YXRlKG1pbiA9IG1pbih2YWx1ZSwgbmEucm0gPSBUKSowLjksCiAgICAgICAgIG1heCA9IG1heCh2YWx1ZSwgbmEucm0gPSBUKSoxLjEpICU+JSAKICBkaXN0aW5jdChsYWJlbCwgLmtlZXBfYWxsID0gVCkgJT4lIAogIHNlbGVjdChsYWJlbCwgbGFiZWxfc2ksIG1pbiwgbWF4KQoKcnVnX2xpbS5maW5hbCA8LSBjaV9ydWdfbGltLmRmICU+JSBsZWZ0X2pvaW4oc2lfcnVnX2xpbS5kZiwgYnkgPSAibGFiZWxfc2kiKSAlPiUgCiAgbXV0YXRlKGZpbmFsX21pbiA9IG1pbihtaW4sIG1pbl9zaSksCiAgICAgICAgIGZpbmFsX21heCA9IG1heChtYXgsIG1heF9zaSkpCgojIGdldCBzZWNvbmQgcnVnX2xpbS5maW5hbCBmb3Igc2luZ2xlIGluZmVjdGlvbgpydWdfbGltLmZpbmFsMiA8LSBydWdfbGltLmZpbmFsICU+JSAKICBncm91cF9ieShsYWJlbF9zaSkgJT4lIAogIG11dGF0ZShmaW5hbF9taW4gPSBtaW4oZmluYWxfbWluLCBuYS5ybSA9IFQpLAogICAgICAgICBmaW5hbF9tYXggPSBtYXgoZmluYWxfbWF4LCBuYS5ybSA9IFQpKQoKIyBmaWx0ZXIgY2lfcm4gYnkgbGltaXQKY2lfcm4uZGYyIDwtIGNpX3JuLmRmICU+JSAKICBsZWZ0X2pvaW4ocnVnX2xpbS5maW5hbCwgYnkgID0gImxhYmVsIikgJT4lIAogIGdyb3VwX2J5KGxhYmVsKSAlPiUgCiAgZmlsdGVyKGN1ZV9yYW5nZSA8PSBmaW5hbF9tYXggJiBjdWVfcmFuZ2UgPj0gZmluYWxfbWluKSAlPiUgCiAgYXJyYW5nZShjdWVfcmFuZ2UsIC5ieV9ncm91cCA9IFQpICU+JSAKICBmaWx0ZXIocm93X251bWJlcigpICUlIDEwID09IDApIApgYGAKCiMgbWF0Y2ggc2luZ2xlIGluZmVjdGlvbiBybiB3aXRoIGNvaW5mZWN0aW9uIApgYGB7cn0KIyBnZXQgY2kgbGFiZWwgdG8gc2kgcnVnIGFuZCBmaWx0ZXIgYnkgbGltaXQKc2lfcm4uZGYyIDwtIGxlZnRfam9pbihzaV9ybi5kZiwgc2VsZWN0KGV6X2xhYmVsLCBsYWJlbF9zaSwgbGFiZWxfY2kpLCBieSA9IGMoImxhYmVsIiA9ICJsYWJlbF9zaSIpKSAlPiUgCiAgbGVmdF9qb2luKHJ1Z19saW0uZmluYWwsIGJ5ICA9IGMoImxhYmVsX2NpIiA9ICJsYWJlbCIpKSAlPiUgCiAgZ3JvdXBfYnkobGFiZWxfY2kpICU+JSAKICBmaWx0ZXIoY3VlX3JhbmdlIDw9IGZpbmFsX21heCAmIGN1ZV9yYW5nZSA+PSBmaW5hbF9taW4pICU+JSAKICBhcnJhbmdlKGN1ZV9yYW5nZSwgLmJ5X2dyb3VwID0gVCkgJT4lIAogIGZpbHRlcihyb3dfbnVtYmVyKCkgJSUgMTAgPT0gMCkgJT4lIAogIHNlbGVjdChjdWVfcmFuZ2UsIGNyLCBsYWJlbF9jaSwgbGFiZWxfc2kpCgojIGdldCBjaSBsYWJlbCB0byBzaSBydWcsIHdlIHdpbGwga2VlcCBvbmUgdW5pcXVlIHZhbHVlIHBlciBsYWJlbApzaV9ydWcuZGYyIDwtIHNlbGVjdChzaV9ydWcuZGYsIHZhbHVlLCBsYWJlbF9zaSA9IGxhYmVsKSAlPiUgZGlzdGluY3QodmFsdWUsIGxhYmVsX3NpKQpgYGAKCiMgcGxvdCByZWFjdGlvbiBub3JtCmBgYHtyfQojIGpvaW4gd2l0aCBlemxhYmVsCmNpX3JuLmRmMyA8LSBjaV9ybi5kZjIgJT4lIGxlZnRfam9pbihlel9sYWJlbCwgYnkgPSBjKCJsYWJlbCIgPSAibGFiZWxfY2kiKSkKc2lfcm4uZGYzIDwtIHNpX3JuLmRmMiAlPiUgbGVmdF9qb2luKGV6X2xhYmVsLCBieSA9ICJsYWJlbF9jaSIpCmNpX3J1Zy5kZjMgPC0gY2lfcnVnLmRmICU+JSBsZWZ0X2pvaW4oZXpfbGFiZWwsIGJ5ID0gYygibGFiZWwiID0gImxhYmVsX2NpIikpCnNpX3J1Zy5kZjMgPC0gc2lfcnVnLmRmMiAlPiUgbGVmdF9qb2luKGV6X2xhYmVsLCBieSA9ICJsYWJlbF9zaSIpCmBgYAoKCmBgYHtyfQojIHJlZG8gb3JkZXIgb2YgY3VlcwpjaV9ybi5kZjMkZXpfbGFiZWwgPC0gZmFjdG9yKGNpX3JuLmRmMyRlel9sYWJlbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkFzZXh1YWwgaVJCQyIsICJBc2V4dWFsIGlSQkMgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUb3RhbCBhc2V4dWFsIGlSQkMiLCAiVG90YWwgYXNleHVhbFxuaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNleHVhbCBpUkJDIiwgIlNleHVhbCBpUkJDIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQXNleHVhbCZzZXh1YWwgaVJCQyIsICJBc2V4dWFsJnNleHVhbFxuaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvdGFsIGlSQkMiLCAiVG90YWwgaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdhbWV0b2N5dGUiLCAiR2FtZXRvY3l0ZSBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvdGFsIGdhbWV0b2N5dGUiLCAiVG90YWwgc2V4dWFsIGlSQkMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSQkMiLCAiUkJDIGxvZzEwIikpIAoKc2lfcm4uZGYzJGV6X2xhYmVsIDwtIGZhY3RvcihzaV9ybi5kZjMkZXpfbGFiZWwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJBc2V4dWFsIGlSQkMiLCAiQXNleHVhbCBpUkJDIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVG90YWwgYXNleHVhbCBpUkJDIiwgIlRvdGFsIGFzZXh1YWxcbmlSQkMgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTZXh1YWwgaVJCQyIsICJTZXh1YWwgaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFzZXh1YWwmc2V4dWFsIGlSQkMiLCAiQXNleHVhbCZzZXh1YWxcbmlSQkMgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUb3RhbCBpUkJDIiwgIlRvdGFsIGlSQkMgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHYW1ldG9jeXRlIiwgIkdhbWV0b2N5dGUgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUb3RhbCBnYW1ldG9jeXRlIiwgIlRvdGFsIHNleHVhbCBpUkJDIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUkJDIiwgIlJCQyBsb2cxMCIpKQoKY2lfcnVnLmRmMyRlel9sYWJlbCA8LSBmYWN0b3IoY2lfcnVnLmRmMyRlel9sYWJlbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkFzZXh1YWwgaVJCQyIsICJBc2V4dWFsIGlSQkMgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUb3RhbCBhc2V4dWFsIGlSQkMiLCAiVG90YWwgYXNleHVhbFxuaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNleHVhbCBpUkJDIiwgIlNleHVhbCBpUkJDIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQXNleHVhbCZzZXh1YWwgaVJCQyIsICJBc2V4dWFsJnNleHVhbFxuaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvdGFsIGlSQkMiLCAiVG90YWwgaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdhbWV0b2N5dGUiLCAiR2FtZXRvY3l0ZSBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvdGFsIGdhbWV0b2N5dGUiLCAiVG90YWwgc2V4dWFsIGlSQkMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSQkMiLCAiUkJDIGxvZzEwIikpCgpzaV9ydWcuZGYzJGV6X2xhYmVsIDwtIGZhY3RvcihzaV9ydWcuZGYzJGV6X2xhYmVsLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiQXNleHVhbCBpUkJDIiwgIkFzZXh1YWwgaVJCQyBsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvdGFsIGFzZXh1YWwgaVJCQyIsICJUb3RhbCBhc2V4dWFsXG5pUkJDIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2V4dWFsIGlSQkMiLCAiU2V4dWFsIGlSQkMgbG9nMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBc2V4dWFsJnNleHVhbCBpUkJDIiwgIkFzZXh1YWwmc2V4dWFsXG5pUkJDIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVG90YWwgaVJCQyIsICJUb3RhbCBpUkJDIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR2FtZXRvY3l0ZSIsICJHYW1ldG9jeXRlIGxvZzEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVG90YWwgZ2FtZXRvY3l0ZSIsICJUb3RhbCBzZXh1YWwgaVJCQyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlJCQyIsICJSQkMgbG9nMTAiKSkKIyBwbG90CmdncGxvdCgpICsKICBnZW9tX2xpbmUoZGF0YSA9IGNpX3JuLmRmMywgYWVzKHggPSBjdWVfcmFuZ2UsIHkgPSBjciwgY29sb3IgPSAiQ28taW5mZWN0aW9uIikpICsKICBnZW9tX3BvaW50KGRhdGEgPSBjaV9ybi5kZjMgJT4lIAogICAgZ3JvdXBfYnkobGFiZWwpICU+JSAKICAgIG11dGF0ZSh0ZW5fdGggPSByb3VuZChuKCkvMTApKSAlPiUgCiAgICBmaWx0ZXIocm93X251bWJlcigpICUlIHRlbl90aCA9PSAwKSwgYWVzKHggPSBjdWVfcmFuZ2UsIHkgPSBjciwgY29sb3IgPSAiQ28taW5mZWN0aW9uIiwgc2hhcGUgPSAiQ28taW5mZWN0aW9uIiksIHNpemUgPSAyKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBzaV9ybi5kZjMsIGFlcyh4ID0gY3VlX3JhbmdlLCB5ID0gY3IsIGNvbG9yID0gIlNpbmdsZSBpbmZlY3Rpb24iKSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHNpX3JuLmRmMyAlPiUgCiAgICBncm91cF9ieShsYWJlbF9jaSkgJT4lIAogICAgbXV0YXRlKHRlbl90aCA9IHJvdW5kKG4oKS8xMCkpICU+JSAKICAgIGZpbHRlcihyb3dfbnVtYmVyKCkgJSUgdGVuX3RoID09IDApLCBhZXMoeCA9IGN1ZV9yYW5nZSwgeSA9IGNyLCBjb2xvciA9ICJTaW5nbGUgaW5mZWN0aW9uIiwgc2hhcGUgPSAiU2luZ2xlIGluZmVjdGlvbiIpLCBzaXplID0gMikgKwogIGdlb21fcnVnKGRhdGEgPSBjaV9ydWcuZGYzLCBhZXMoeCA9IHZhbHVlKSwgY29sb3IgPSAiIzQ1NzViNCIsIHNpZGVzID0gInQiLCBsZW5ndGggPSB1bml0KDAuMSwgIm5wYyIpKSArCiAgZ2VvbV9ydWcoZGF0YSA9IHNpX3J1Zy5kZjMsIGFlcyh4ID0gdmFsdWUpLCBjb2xvciA9ICIjZmM4ZDU5Iiwgc2lkZXMgPSAiYiIsIGxlbmd0aCA9IHVuaXQoMC4xLCAibnBjIikpICsKICBmYWNldF93cmFwKH5lel9sYWJlbCwgc2NhbGVzID0gImZyZWVfeCIsIG5jb2wgPSAyKSArCiAgeWxpbSgtMC4zLCAxLjMpICsKICB0aGVtZV9idygpICsKICBsYWJzKHkgPSAiQ29udmVyc2lvbiByYXRlIiwgeCA9ICJDdWUgcmFuZ2UiLCBjb2xvciA9ICJNb2RlbCIsIHNoYXBlID0gIk1vZGVsIikgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFQpLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMoY2hlY2sub3ZlcmxhcCA9IFRSVUUpKSArIAogICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA3KSwKICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKSAgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YyggIiM0NTc1YjQiLCAiI2ZjOGQ1OSIpKSArCiAgdGhlbWUoc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbihiID0gMC41LCB0ID0gMC41KSkpCgpnZ3NhdmUodW5pdHMgPSAicHgiLCBkcGkgPSAzMDAsIHdpZHRoID0gMjAwMCwgaGVpZ2h0ID0gMjUwMCwgZmlsZW5hbWUgPSBoZXJlKCJmaWd1cmVzL3Bsb3MtYmlvL3JlYWN0aW9uX25vcm0udGlmZiIpLCBiZyA9ICJ3aGl0ZSIsIHNjYWxlID0gMS4xKQpgYGAKCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKUGxvdHRpbmcgc2luZ2xlIGFuZCBjby1pbmZlY3Rpb24gZml0bmVzcyBzY2F0dGVyIHBsb3QKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwojIGltcG9ydCBpbiBkYXRhCmBgYHtyfQojIHNpbmdsZSBpbmZlY3Rpb24gZHluYW1pY3MKc2lfZHluLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL3NpX2R5bi9zaV9keW5fMzAucGFycXVldCIpKSAKCiMgY28taW5mZWN0aW9uIGR5bmFtaWNzCmNpX2R5bi5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9jaV9keW4vY2lfZHluLnBhcnF1ZXQiKSkKCmV6X2xhYmVsIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvZXpfbGFiZWwuY3N2IikpCmBgYAoKIyBwcm9jZXNzIGZvciBmaW5hbCAyMCBkYXlzIGZpdG5lc3MKYGBge3J9CiMgZ2V0IHNpbmdsZSBpbmZlY3Rpb24gbWF4aW11bSB0YXVfY3VtIGZvciAyMCBkYXlzCnNpX2ZpdG5lc3MuZGYgPC0gc2lfZHluLmRmICU+JSAKICBmaWx0ZXIodmFyaWFibGUgPT0gInRhdV9jdW0iICYgdGltZSA9PSAyMCkKCiMgZ2V0IGNvLWluZmVjdGlvbiBtYXhpbXVtIHRhdV9jdW0gZm9yIDIwIGRheXMKY2lfZml0bmVzcy5kZiA8LSBjaV9keW4uZGYgJT4lIAogIGZpbHRlcih2YXJpYWJsZSA9PSAidGF1X2N1bTEiICYgdGltZSA9PSAyMCkKCiMgam9pbiB0b2dldGhlciB0d28gZGF0YWZyYW1lcyBhbmQgYWRkIGxhYmVscwpzaV9jaV9maXRuZXNzLmRmIDwtIHNlbGVjdChjaV9maXRuZXNzLmRmLCBmaXRuZXNzX2NpID0gdmFsdWUsIGxhYmVsX2NpID0gbGFiZWwpICU+JSAKICBsZWZ0X2pvaW4oZXpfbGFiZWwsIGJ5ID0gImxhYmVsX2NpIikgJT4lIAogIGxlZnRfam9pbihzZWxlY3Qoc2lfZml0bmVzcy5kZiwgZml0bmVzc19zaSA9IHZhbHVlLCBpZF9zaSA9IGlkKSwgYnkgPSAiaWRfc2kiKSAlPiUgCiAgc2VsZWN0KGV6X2xhYmVsX3NpLCBlel9sYWJlbCwgZml0bmVzc19zaSwgZml0bmVzc19jaSkgJT4lIAogIHJiaW5kKGRhdGEuZnJhbWUoICMgYWRkIHRpbWUKICAgIGV6X2xhYmVsX3NpID0gIlRpbWUiLCAKICAgIGV6X2xhYmVsID0gIlRpbWUiLAogICAgZml0bmVzc19zaSA9ICA5Ljc4Nzg5OSwKICAgIGZpdG5lc3NfY2kgID0gMi4zMTE4NDEKICApKQoKc2lfY2lfZml0bmVzcy5kZgpgYGAKCiMgcGxvdCBzY2F0dGVyIHBvaW50IG9mIHNpbmdsZSBpbmZlY3Rpb24gdnMgY28taW5mZWN0aW9uCmBgYHtyfQpzaV9jaV9maXRuZXNzLnBsIDwtIGdncGxvdCgpICsKICBnZW9tX3BvaW50KGRhdGEgPSBzaV9jaV9maXRuZXNzLmRmLCBhZXMoeCA9IGZpdG5lc3Nfc2ksIHkgPSBmaXRuZXNzX2NpLCBjb2xvciA9IGV6X2xhYmVsX3NpLCBzaGFwZSA9IGV6X2xhYmVsX3NpKSwgc2l6ZSA9IDMuNSkgKwogIGdncmVwZWw6Omdlb21fbGFiZWxfcmVwZWwoZGF0YSA9IHNpX2NpX2ZpdG5lc3MuZGYsIGFlcyhsYWJlbCA9IGV6X2xhYmVsLCB4ID0gZml0bmVzc19zaSwgeSA9IGZpdG5lc3NfY2kpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJ3aGl0ZSIseGxpbSA9IGMoLUluZiwgSW5mKSwgeWxpbSA9IGMoTkEsIE5BKSkgKwogIGxhYnMoeCA9ICJNYXhpbXVtIHNpbmdsZSBpbmZlY3Rpb24gZml0bmVzcyIsIHkgPSAiTWF4aW11bSBDby1pbmZlY3Rpb24gZml0bmVzcyAocGVyIHN0cmFpbikiLAogICAgICAgY29sb3IgPSAiU2luZ2xlIGluZmVjdGlvbiBjdWUiLCBzaGFwZSA9ICJTaW5nbGUgaW5mZWN0aW9uIGN1ZSIpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gMTU6MjUpICsKICBsaW1zKHggPSBjKDgsIDEwLjMpKSArCiAgdGhlbWVfYncoKQpgYGAKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIyB0aW1lIHNlcmllcyBjb252ZXJzaW9uIHJhdGUgZm9yIHNpbmdsZSBhbmQgY28taW5mZWN0aW9uCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMtLS0tLS0tLS1nZXQgImlkZWFsIiBzaW5nbGUgaW5mZWN0aW9uIGFuZCBjby1pbmZlY3Rpb24gZHluYW1pY3MtLS0tLS0tLS0jClRoaXMgaXMgd2hlbiBzdHVmZiBhcmUgb3B0aW1pemVkIGJhc2VkIG9uIHRpbWUKYGBge3J9CnNvdXJjZShoZXJlKCJmdW5jdGlvbnMvY2hhYmF1ZGlfc2lfY2xlYW4uUiIpKQpzb3VyY2UoaGVyZSgiZnVuY3Rpb25zL2NoYWJhdWRpX2NpX2NsZWFuLlIiKSkKCiMgc2luZ2xlIGluZmVjdGlvbiBkeW5hbWljIHdpdGggdGltZSBhcyBjdWUuIE9wdGltaXplZCB1c2luZyBsb2NhbCBvcHRpbWl6ZXIuIE5vdGUgdGhhdCB0aGUgdGltZSB2YXJpYWJsZSBpbiBkdWFsIGN1ZSBpcyBzbGlnaHRseSBkaWZmZXJlbnQgd2l0aCBoaWdoZXIgZmxleGliaWxpdHkuIFdoaWxlIHRoYXQgaW5jcmVhc2VzIHRoZSBmaXRuZXNzIHZhbHVlIGJ5IH4wLjEsIHRoZSBvdmVyYWxsIGNvbnZlcnNpb24gcmF0ZSBkeW5hbWljIGRvZXMgbm90IGNoYW5nZSB0aGF0IG11Y2gKc2lfdC5kZiA8LSBjaGFiYXVkaV9zaV9jbGVhbigKICBwYXJhbWV0ZXJzX2NyID0gYyg0LjU1Mzg2LCAtMTMuMDA1NiwgNC4xNTQ2NiwgLTExLjk0MjQpLAogIGltbXVuaXR5ID0gInRzdWt1c2hpIiwKICBwYXJhbWV0ZXJzID0gcGFyYW1ldGVyc190c3VrdXNoaSwKICB0aW1lX3JhbmdlID0gc2VxKDAsIDIwLCBieSA9IDFlLTMpLAogIGN1ZV9yYW5nZSA9ICBzZXEoMCwgMjAsIGJ5ID0gMWUtMyksCiAgY3VlID0gInQiLAogIHNvbHZlciA9ICJ2b2RlIiwKICBkeW4gPSBUKQoKIyBjby1pbmZlY3Rpb24gZHluYW1pYyB3aXRoIHRpbWUgYXMgY3VlCmNpX3QuZGYgPC0gY2hhYmF1ZGlfY2lfY2xlYW4ocGFyYW1ldGVyc19jcl8xID0gYygyNi4xNjQyNSwJLTcxLjA3Nzk5LAk1My4zNDEyMSwJLTE2Ni4yNTY5MyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbWV0ZXJzX2NyXzIgPSBjKDI2LjE2NDI1LAktNzEuMDc3OTksCTUzLjM0MTIxLAktMTY2LjI1NjkzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGltbXVuaXR5ID0gInRzdWt1c2hpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtZXRlcnMgPSBwYXJhbWV0ZXJzX3RzdWt1c2hpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGltZV9yYW5nZSA9IHRpbWVfcmFuZ2UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VlXzEgPSAgInQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VlXzI9ICJ0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1ZV9yYW5nZV8xID0gdGltZV9yYW5nZSwgIyBjdWUgcmFuZ2Ugb2Ygc3RyYWluIDEKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1ZV9yYW5nZV8yID0gdGltZV9yYW5nZSwgIyBjdWUgcmFuZ2Ugb2Ygc3RyYWluIDIKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ19jdWVfMSA9ICJub25lIiwgIyB3aGV0aGVyIHRvIGxvZyB0cmFuc2Zvcm0gY3VlIDEKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ19jdWVfMiA9ICJub25lIiwgIyB3aGV0aGVyIHRvIGxvZyB0cmFuc2Zvcm0gY3VlIDIKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNvbHZlciA9ICJ2b2RlIiwgIyBzb2x2ZXIgZm9yIG51bWVyaWNhbCBpbnRlZ3JhdGlvbi4gVm9kZSBvZnRlbiBnaXZlcyBmYXN0ZXIgcnVucwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkeW4gPSBUKQoKIyBnZXQgb25seSBjb252ZXJzaW9uIHJhdGUgYW5kIG1ha2Ugc2FtZSBmb3JtYXQgYXMgc2lfY3IuZGYyL2NpX2NyLmRmMgpzaV90LmRmICU+JSBmaWx0ZXIodGltZSA9PSAyMCAmIHZhcmlhYmxlID09ICJ0YXVfY3VtIikgIyMgZml0bmVzcyB2YWx1ZSBvZiB0aW1lIGFzIGN1ZSBpbiBzaW5nbGUgaW5mZWN0aW9uCnNpX3QuY3IgPC0gc2lfdC5kZiAlPiUgCiAgZmlsdGVyKHZhcmlhYmxlID09ICJjciIpICU+JSAKICBtdXRhdGUoZXpfbGFiZWxfc2kgPSAiVGltZSIsIAogICAgICAgICBmaXRuZXNzX3NpID05Ljc4Nzg5OSkgJT4lIAogIHNlbGVjdCh0aW1lLCB2YWx1ZSwgZml0bmVzc19zaSwgZXpfbGFiZWxfc2kpCgoKIyMgZ2V0IGZpdG5lc3MgdmFsdWUgb2YgY28taW5mZWN0aW9uIHRpbWUKY2lfdC5kZiAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJ0YXVfY3VtMSIpICU+JSBzdW1tYXJpemUobWF4ID0gbWF4KHZhbHVlLCBuYS5ybSA9IFQpKQpjaV90LmNyIDwtIGNpX3QuZGYgJT4lIAogIGZpbHRlcih2YXJpYWJsZSA9PSAiY3JfMSIpICU+JSAKICBtdXRhdGUoZXpfbGFiZWwgPSAiVGltZSIsIAogICAgICAgICBmaXRuZXNzX2NpID0gMi4zMTE4NDEsCiAgICAgICAgIGxhYmVsID0gIlRpbWUiKSAlPiUKICBzZWxlY3QodGltZSwgdmFsdWUsIGZpdG5lc3NfY2ksIGV6X2xhYmVsLCBsYWJlbCkKYGBgCgojLS0tLS0tLS0tIHNpbmdsZSBpbmZlY3Rpb24gY29udmVyc2lvbiByYXRlIGhlYXQgbWFwLS0tLS0tLS0tLS0tLS0jCiMgcHJvY2VzcyBpbmZvIGZvciBzaW5nbGUgaW5mZWN0aW9uCmBgYHtyfQojIGdldCBjb252ZXJzaW9uIHJhdGUgZHluYW1pY3MKc2lfY3IuZGYgPC0gc2lfZHluLmRmICU+JSAKICBmaWx0ZXIodGltZSA8PSAyMCAmIHZhcmlhYmxlID09ICJjciIpCgojIGdldCB0aW1lIHJhbmdlcy4gV2Ugd2lsbCBvbWl0IGFueSB2YWx1ZXMgd2hlcmUgSSBpcyBiZWxvdyAxMDAuIE5vdGUgZm9yIGFsbCBzaW5nbGUgaW5mZWN0aW9uLCBpdCBpcyBmb3JtICAwLjU1IHRvIDIwLiBOb3RlIHdlIGFyZSBub3QgZG9pbmcgSStJZyBiZWNhdXNlIGNvbnZlcnNpb24gcmF0ZSBpcyBvbmx5IHJlbGV2ZW50IHdoZW4gYXNleHVhbCBpUkJDIGlzIGFyb3VuZCB0byBkaWZmZXJlbnRpYXRlIQpzaV9keW4uZGYgJT4lIAogIGZpbHRlcih0aW1lIDw9IDIwICYgdmFyaWFibGUgPT0gIkkiICYgdmFsdWUgPiAxMDApICU+JQogIGdyb3VwX2J5KGlkKSAlPiUgCiAgc3VtbWFyaXplKG1pbl90aW1lID0gbWluKHRpbWUpLAogICAgICAgICAgICBtYXhfdGltZSA9IG1heCh0aW1lKSkKCiMgam9pbiBmaXRuZXNzIGFuZCBpZGVhbCBkeW5hbWljcwpzaV9jci5kZjIgPC0gc2lfY3IuZGYgJT4lIAogIGxlZnRfam9pbihzZWxlY3Qoc2lfZml0bmVzcy5kZiwgaWQsIGZpdG5lc3Nfc2kgPSB2YWx1ZSksIGJ5ID0gImlkIikgJT4lIAogIGxlZnRfam9pbihlel9sYWJlbCwgYnkgPSBjKCJpZCIgPSAiaWRfc2kiKSkgJT4lIAogIHNlbGVjdCh0aW1lLCB2YWx1ZSwgZml0bmVzc19zaSwgZXpfbGFiZWxfc2kpICU+JSAKICByYmluZChzaV90LmNyKSAjIGpvaW4gd2l0aCBkYXRhZnJhbWUgY29udGFpbmluZyBpZGVhbCBkeW5hbWljcwoKIyBwbG90LiBub3RlIHRoYXQgd2UgYXJlIG9taXR0aW5nIGRheSAxIGNvbnZlcnNpb24gcmF0ZSBkeW5hbWljIGJlY2F1c2UgYWxsIGNyIGF0IHRoYXQgc3RhZ2UgaXMgMCAoYnkgbW9kZWwgZGVmYXVsdCkKc2lfY3IucGwgPC0gZ2dwbG90KGRhdGEgPSBzaV9jci5kZjIsIGFlcyh4ID0gdGltZSwgeSA9IGZvcmNhdHM6OmZjdF9yZW9yZGVyKGV6X2xhYmVsX3NpLCBmaXRuZXNzX3NpKSkpICsKICBnZW9tX3Jhc3RlcihhZXMoZmlsbCA9IHZhbHVlKSkgKwogIGxhYnMoeCA9ICJUaW1lIChkYXlzKSIsIHkgPSAiU2luZ2xlIGluZmVjdGlvbiBjdWVzIiwgZmlsbCA9ICJDb252ZXJzaW9uIHJhdGUiKSArCiAgdmlyaWRpczo6c2NhbGVfZmlsbF92aXJpZGlzKGxpbWl0cyA9IGMoMCwgMSksIG9vYiA9IHNjYWxlczo6c3F1aXNoKSArCiAgeGxpbSgxLCAyMCkgKwogIHRoZW1lX2J3KCkKYGBgCgojIC0tLS0tLS0tLS0tLS0tLS0tY28taW5mZWN0aW9uIGNvbnZlcnNpb24gcmF0ZSBoZWF0bWFwLS0tLS0tLS0tLS0jCiMgcGxvdCBjby1pbmZlY2l0b24gY29udmVzaW9uIHJhdGUgaGVhdG1hcApgYGB7cn0KIyBnZXQgY29udmVyc2lvbiByYXRlIGR5bmFtaWNzCmNpX2NyLmRmIDwtIGNpX2R5bi5kZiAlPiUgCiAgZmlsdGVyKHRpbWUgPD0gMjAgJiB2YXJpYWJsZSA9PSAiY3JfMSIpCgojIGdldCB0aW1lIHJhbmdlIHRvIGluY2x1ZGUuIFNhbWUgY3JpdGVyaWEuIHdlIG5lZWQgaWYgc2luZ2xlIHN0cmFpbiBwb3B1bGF0aW9uIGRlY2xpbmVzIHRvIGxlc3MgdGhhbiAxMDAKIyMgd2hlbiB0aW1lIGlzIHVzZWQgYXMgYSBjdWU6IDEyLjk0MwpjaV90LmRmICU+JQogIGZpbHRlcih0aW1lIDw9IDIwICYgdmFyaWFibGUgPT0gIkkxIiAmIHZhbHVlID4gMTAwKSAlPiUgCiAgc3VtbWFyaXplKG1heF90aW1lID0gbWF4KHRpbWUpKQojIyBhbGwgb3RoZXIgZHluYW1pY3MKY2lfY3IudGltZSA8LSBjaV9keW4uZGYgJT4lIAogIGZpbHRlcih0aW1lIDw9IDIwICYgdmFyaWFibGUgPT0gIkkxIiAmIHZhbHVlID4gMTAwKSAlPiUgCiAgZ3JvdXBfYnkobGFiZWwpICU+JSAKICBzdW1tYXJpemUobWF4X3RpbWUgPSBtYXgodGltZSkpICU+JSAKICByYmluZChkYXRhLmZyYW1lKGxhYmVsID0gIlRpbWUiLCBtYXhfdGltZSA9IDEyLjk0MykpCgojIGpvaW4gd2l0aCBmaXRuZXNzLCBpZGVhbCBkeW5hbWljcyBhbmQgYWxzbyBtYXhpbXVtIHRpbWUgcmFuZ2UgY29uc2lkZXJlZApjaV9jci5kZjIgPC0gY2lfY3IuZGYgJT4lIAogIGxlZnRfam9pbihzZWxlY3QoY2lfZml0bmVzcy5kZiwgbGFiZWwsIGZpdG5lc3NfY2kgPSB2YWx1ZSksIGJ5ID0gImxhYmVsIikgJT4lIAogIGxlZnRfam9pbihlel9sYWJlbCwgYnkgPSBjKCJsYWJlbCIgPSAibGFiZWxfY2kiKSkgJT4lIAogIHNlbGVjdCh0aW1lLCB2YWx1ZSwgZml0bmVzc19jaSwgZXpfbGFiZWwsIGxhYmVsKSAlPiUgCiAgcmJpbmQoY2lfdC5jcikgJT4lICMgYmluZCBpZGVhbCBkeW5hbWljcwogIGxlZnRfam9pbihjaV9jci50aW1lLCBieSA9ICJsYWJlbCIpICU+JSAKICBmaWx0ZXIodGltZSA8PSBtYXhfdGltZSkgIyBrZWVwIG9ubHkgdGhvc2UgdGhhdCBhcmUgd2l0aGluIHRpbWUgcmFuZ2UKCiMgcGxvdApjaV9jci5wbCA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9yYXN0ZXIoZGF0YSA9IGNpX2NyLmRmMiwgCiAgICAgICAgICAgICAgYWVzKHggPSB0aW1lLCB5ID0gZm9yY2F0czo6ZmN0X3Jlb3JkZXIoZXpfbGFiZWwsIGZpdG5lc3NfY2kpLCBmaWxsID0gdmFsdWUpKSArCiAgbGFicyh4ID0gIlRpbWUgKGRheXMpIiwgeSA9ICJDby1pbmZlY3Rpb24gY3VlcyIsIGZpbGwgPSAiQ29udmVyc2lvbiByYXRlIikgKwogIHZpcmlkaXM6OnNjYWxlX2ZpbGxfdmlyaWRpcyhsaW1pdHMgPSBjKDAsIDEpLCBvb2IgPSBzY2FsZXM6OnNxdWlzaCkgKwogIHhsaW0oMSwgMjApICsKICB0aGVtZV9idygpCmBgYAoKIy0tLS0tLS0tLSBhc3NlbWJsZSBmaW5hbCBmaWd1cmUgLS0tLS0tLS0tLS0tLS0jCmBgYHtyfQojIGNvbWJpbmUgY29udmVyc2lvbiByYXRlIGR5bmFtaWMgb2Ygc2luZ2xlIGluZmVjdGlvbiBhbmQgY28taW5mZWN0aW9uCmNyLnBsIDwtIGdnYXJyYW5nZShzaV9jci5wbCwgY2lfY3IucGwsIGxhYmVscyA9IGMoIkIiLCAiQyIpLCBuY29sID0gMiwgY29tbW9uLmxlZ2VuZCA9IFQsIGFsaWduID0gImgiKQoKIyBjb21iaW5lIHdpdGggZml0bmVzcyBzY2F0dGVycGxvdApnZ2FycmFuZ2Uoc2lfY2lfZml0bmVzcy5wbCwgY3IucGwsIG5jb2wgPSAxLCBsYWJlbHMgPSBjKCJBIiwgIiIpLCBhbGlnbiA9ICJodiIpCgojIHNhdmUKZ2dzYXZlKHVuaXRzID0gInB4IiwgZHBpID0gMzAwLCB3aWR0aCA9IDIwMDAsIGhlaWdodCA9IDIwMDAsIGZpbGVuYW1lID0gaGVyZSgiZmlndXJlcy9wbG9zLWJpby9maXRuZXNzX2NyLWR5bi50aWZmIiksIGJnID0gIndoaXRlIiwgc2NhbGUgPSAxLjM1KQpgYGAKCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIyBEZW1vZ3JhcGhpYyBzdG9jaGFzdGljaXR5CiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIy0tLS0tLS0tLS0gcGxvdCBoZWF0IG1hcC0tLS0tLS0tLS0tLS0tLSMKIyBpbXBvcnQgaW4gYWxsIGZpdG5lc3MgZmlsZXMKYGBge3J9CmZpbGVfbHMgPC0gbGlzdC5maWxlcyhwYXRoID0gaGVyZSgiZGF0YS9NQ19wYXJ0aXRpb25lZC8iKSwgcGF0dGVybiA9ICIqLmNzdiIsIGZ1bGwubmFtZXMgPSBUKQpuYW1lX2xzIDwtIGxpc3QuZmlsZXMocGF0aCA9IGhlcmUoImRhdGEvTUNfcGFydGl0aW9uZWQvIiksIHBhdHRlcm4gPSAiKi5jc3YiKQpuYW1lX2xzIDwtIGdzdWIoIiouY3N2IiwgIiIsIG5hbWVfbHMpCgojIDYwLCB3aGljaCBpcyBhYm91dCByaWdodApsZW5ndGgoZmlsZV9scykKCiMgcmVhZCBpbiBmaWxlcwpmaXRuZXNzLmxzIDwtIGxhcHBseShmaWxlX2xzLCByZWFkLmNzdikKCiMgYXNzaWduIHVuaXF1ZSBJRApmaXRuZXNzLmxzIDwtIG1hcHBseShjYmluZCwgZml0bmVzcy5scywgIklEIiA9IG5hbWVfbHMsIFNJTVBMSUZZID0gRikKYGBgCgojIHByb2Nlc3MgZGF0YQpgYGB7cn0KIyBnZXQgbWV0YWluZm8gZnJvbSBJRApmaXRuZXNzLmxzMiA8LSBtY2xhcHBseShmaXRuZXNzLmxzLCBmdW5jdGlvbih4KXsKICBpZF9jb2wgPC0geCRJRAogICMgc3RyaW5nIHNwbGl0IHRvIGV4dHJhY3QgYWxsIGluZm8KICBjdWUgPC0gdW5saXN0KHN0cl9zcGxpdCh1bmlxdWUoaWRfY29sKSwgcGF0dGVybiA9ICJfIikpW1szXV0KICBsb2cgPC0gdW5saXN0KHN0cl9zcGxpdCh1bmlxdWUoaWRfY29sKSwgcGF0dGVybiA9ICJfIikpW1s0XV0KICByYW5kX3ZhciA8LSB1bmxpc3Qoc3RyX3NwbGl0KHVuaXF1ZShpZF9jb2wpLCBwYXR0ZXJuID0gIl8iKSlbWzVdXQogIAogICMgZ2V0IG1lYW4KICBtZWFuX2ZpdG5lc3MgPC0gbWVhbih4JG1heF9maXRuZXNzKQogICMgZ2V0IHNkCiAgc2RfZml0bmVzcyA8LSBzZCh4JG1heF9maXRuZXNzKQogIAogICMgYmluZCByZXN1bHRzCiAgcmVzIDwtIGNiaW5kKHgsIGN1ZT0gY3VlLCBsb2cgPSBsb2csIHJhbmRfdmFyID0gcmFuZF92YXIsIG1lYW5fZml0bmVzcyA9IG1lYW5fZml0bmVzcywgc2RfZml0bmVzcyA9IHNkX2ZpdG5lc3MpCiAgcmV0dXJuKHJlcykKfSkKYGBgCgojIEdldCByZWZlcmVuY2UgZGF0YQpgYGB7cn0KcmVmZXJlbmNlX2xzIDwtIGxpc3QuZmlsZXMocGF0aCA9IGhlcmUoImRhdGEvTUMyIiksIHBhdHRlcm4gPSAiKi5jc3YiLCBmdWxsLm5hbWVzID0gVCkKcmVmZXJlbmNlX25hbWUubHMgPC0gZ3N1YigiKi5jc3YiLCAiIiwgbGlzdC5maWxlcyhwYXRoID0gaGVyZSgiZGF0YS9NQzIvIiksIHBhdHRlcm4gPSAiKi5jc3YiKSkKCiMgcmVhZCBpbiB0aGUgZmlsZXMKcmVmZXJlbmNlLmxzIDwtIGxhcHBseShyZWZlcmVuY2VfbHMsIHJlYWQuY3N2KQoKIyBhc3NpZ24gdW5pcXVlIElECnJlZmVyZW5jZS5scyA8LSBtYXBwbHkoY2JpbmQsIHJlZmVyZW5jZS5scywgIklEIiA9IHJlZmVyZW5jZV9uYW1lLmxzLCBTSU1QTElGWSA9IEYpCgojIGdldCBtZXRhIGRhdGEKcmVmZXJlbmNlLmxzMiA8LSBtY2xhcHBseShyZWZlcmVuY2UubHMsIGZ1bmN0aW9uKHgpewogIGlkX2NvbCA8LSB4JElECiAgIyBzdHJpbmcgc3BsaXQgdG8gZXh0cmFjdCBhbGwgaW5mbwogIGN1ZSA8LSB1bmxpc3Qoc3RyX3NwbGl0KHVuaXF1ZShpZF9jb2wpLCBwYXR0ZXJuID0gIl8iKSlbWzJdXQogICMgZ2V0IGxvZwogIHRoaXJkX2NvbCA8LSB1bmxpc3Qoc3RyX3NwbGl0KHVuaXF1ZShpZF9jb2wpLCBwYXR0ZXJuID0gIl8iKSlbWzNdXQogIGxvZyA8LSBpZmVsc2UodGhpcmRfY29sID09ICJsb2ciLCAibG9nMTAiLCAibm9uZSIpCiAgCiAgIyBnZXQgbWVhbgogIG1lYW5fZml0bmVzcyA8LSBtZWFuKHgkbWF4X2ZpdG5lc3MpCiAgCiAgIyBnZXQgc2QKICBzZF9maXRuZXNzIDwtIHNkKHgkbWF4X2ZpdG5lc3MpCiAgCiAgIyBiaW5kIHJlc3VsdHMKICByZXMgPC0gY2JpbmQoeCwgY3VlPSBjdWUsIGxvZyA9IGxvZywgcmFuZF92YXIgPSAiYWxsIiwgcmVmX21lYW5fZml0bmVzcyA9IG1lYW5fZml0bmVzcywgcmVmX3NkX2ZpdG5lc3MgPSBzZF9maXRuZXNzKQogIHJldHVybihyZXMpCn0pCmBgYAoKIyBjb21iaW5lIE1DIHBhcnRpdGlvbmVkIGFuZCByZWZlcmVuY2UgZGYKYGBge3J9CiMgZ2V0IHVuaXF1ZSBjb2x1bW4gdmFsdWVzIGZvciBlYWNoIGN1ZSwgbG9nLCBhbmQgcmFuZF92YXIgY29tYm8KZml0bmVzcy5sczMgPC0gZG8uY2FsbChyYmluZCwgZml0bmVzcy5sczIpCmZpdG5lc3MubHMzIDwtIGZpdG5lc3MubHMzICU+JSBkcGx5cjo6ZGlzdGluY3QoSUQsIC5rZWVwX2FsbCA9IFQpCgojIHJlcGVhdCB3aXRoIHJlZmVyZW5jZQpyZWZlcmVuY2UubHMzIDwtIGRvLmNhbGwocmJpbmQsIHJlZmVyZW5jZS5sczIpCnJlZmVyZW5jZS5sczMgPC0gcmVmZXJlbmNlLmxzMyAlPiUgZHBseXI6OmRpc3RpbmN0KElELCAua2VlcF9hbGwgPSBUKQoKIyBjb21iaW5lIQpyZWZfZml0LmRmIDwtIGxlZnRfam9pbihmaXRuZXNzLmxzMywgcmVmZXJlbmNlLmxzMywgYnkgPSBjKCJjdWUiID0gImN1ZSIsICJsb2ciPSAibG9nIikpCmBgYAoKIyBjb21wdXRlIHByb3BvcnRpb24gZml0bmVzcyBhbmQgdmFyaWF0aW9uCmBgYHtyfQpyZWZfZml0LmRmMiA8LSByZWZfZml0LmRmICU+JSAKICBtdXRhdGUocF9zZCA9IHNkX2ZpdG5lc3MvcmVmX3NkX2ZpdG5lc3MsCiAgICAgICAgIHBfbWVhbiA9IHJlZl9tZWFuX2ZpdG5lc3MvbWVhbl9maXRuZXNzLAogICAgICAgICBjdWVfbG9nID0gcGFzdGUwKGN1ZSwgIl8iLCBsb2cpLAogICAgICAgICBsYWJlbCA9IGNhc2Vfd2hlbigKICAgICAgICAgICBjdWUgPT0gIkciIH4gIkdhbWV0b2N5dGUiLAogICAgICAgICAgIGN1ZSA9PSAiSSIgfiAiQXNleHVhbCBpUkJDIiwKICAgICAgICAgICBjdWUgPT0gIkkrSWciIH4gIkFzZXh1YWwmc2V4dWFsXG5pUkJDIiwKICAgICAgICAgICBjdWUgPT0gIklnIiB+ICJTZXh1YWwgaVJCQyIsCiAgICAgICAgICAgY3VlID09ICJSIiB+ICJSQkMiCiAgICAgICAgICAgKSwKICAgICAgICAgcGFyYW1ldGVyID0gY2FzZV93aGVuKAogICAgICAgICAgIHJhbmRfdmFyLnggPT0gInJobyIgfiAiUkJDIHJlcGxlbmlzaG1lbnQgKM+BKSIsCiAgICAgICAgICAgcmFuZF92YXIueCA9PSAicGhpbiIgfiAiSGFsZi1saWZlIGluZGlzICjPlW4pIiwKICAgICAgICAgICByYW5kX3Zhci54ID09ICJwaGl3In4gIkhhbGYtbGlmZSB0YXJnZXRlZCAoz5V3KSIsCiAgICAgICAgICAgcmFuZF92YXIueCA9PSAicHNpbiIgfiAiQWN0aXZhdGlvbiBpbmRpcyAoz4huKSIsCiAgICAgICAgICAgcmFuZF92YXIueCA9PSAicHNpdyIgfiAiQWN0aXZhdGlvbiB0YXJnZXRlZCAoz4h3KSIsCiAgICAgICAgICAgcmFuZF92YXIueCA9PSAiYmV0YSIgfiAiQnVyc3Qgc2l6ZSAozrIpIgogICAgICAgICApKQpgYGAKCiMgcGxvdCEKYGBge3J9CiMgdmFyaWF0aW9uCm1jX2IgPC0gZ2dwbG90KCkgKwogIGdlb21fdGlsZShkYXRhID0gcmVmX2ZpdC5kZjIgLCBhZXMoeCA9IGxhYmVsLCB5ID0gcGFyYW1ldGVyLCBmaWxsID0gcF9zZCkpICsKICBmYWNldF93cmFwKH5sb2cpICsKICB0aGVtZV9idygpICsKICB2aXJpZGlzOjpzY2FsZV9maWxsX3ZpcmlkaXMoKSArCiAgbGFicyh4ID0gIkN1ZSIsIHkgPSAiUGFyYW1ldGVyIHJhbmRvbWl6ZWQiLCBmaWxsID0gZXhwcmVzc2lvbihmcmFjKHNkKCIxIHBhcmFtZXRlciByYW5kb21pemVkIiksIHNkKCJhbGwgcGFyYW1ldGVycyByYW5kb21pemVkIikpKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0idG9wIiwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdD0xKSkKCiMgbWVhbiBmaXRuZXNzCm1jX2MgPC0gZ2dwbG90KCkgKwogIGdlb21fdGlsZShkYXRhID0gcmVmX2ZpdC5kZjIgLCBhZXMoeCA9IGxhYmVsLCB5ID0gcGFyYW1ldGVyLCBmaWxsID0gcF9tZWFuKSkgKwogIGZhY2V0X3dyYXAofmxvZykgKwogIHRoZW1lX2J3KCkgKwogIHZpcmlkaXM6OnNjYWxlX2ZpbGxfdmlyaWRpcygpICsKICBsYWJzKHggPSAiQ3VlIiwgeSA9ICJQYXJhbWV0ZXIgcmFuZG9taXplZCIsIGZpbGwgPSBleHByZXNzaW9uKGZyYWMoTWVhbigiYWxsIHBhcmFtZXRlcnMgcmFuZG9taXplZCIpLCBNZWFuKCIxIHBhcmFtZXRlciByYW5kb21pemVkIikpKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0idG9wIiwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdD0xKSkKCm1jX3BhcnRpdGlvbiA8LSBnZ2FycmFuZ2UobWNfYiwgbWNfYywgbmNvbCA9IDEpCgpgYGAKCiMtLS0tLS0tLS0tLS0tLSBnZXQgdmlvbGluZSBwbG90IG9mIHZhcmlhdGlvbiBpbiBmaXRuZXNzIC0tLS0tLS0tLS0tLS0tLS0tLS0tIwojIHJlYWQgTUMgZGF0YQpgYGB7cn0KIyByZWFkIGluIGR5bWFtaWNzCm1jX0dfbG9nLmR5biA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9NQzIvbWNfR19sb2dfZHluLnBhcnF1ZXQiKSkKbWNfRy5keW4gPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvTUMyL21jX0dfZHluLnBhcnF1ZXQiKSkKbWNfUl9sb2cuZHluIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL01DMi9tY19SX2xvZ19keW4ucGFycXVldCIpKQptY19SLmR5biA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9NQzIvbWNfUl9keW4ucGFycXVldCIpKQptY19JX2xvZy5keW4gPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvTUMyL21jX0lfbG9nX2R5bi5wYXJxdWV0IikpCm1jX0kuZHluIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL01DMi9tY19JX2R5bi5wYXJxdWV0IikpCm1jX0lnX2xvZy5keW4gPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvTUMyL21jX0lnX2xvZ19keW4ucGFycXVldCIpKQptY19JZy5keW4gPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvTUMyL21jX0lnX2R5bi5wYXJxdWV0IikpCm1jX0lfSWdfbG9nLmR5biA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9NQzIvbWNfSStJZ19sb2dfZHluLnBhcnF1ZXQiKSkKbWNfSV9JZy5keW4gPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvTUMyL21jX0krSWdfZHluLnBhcnF1ZXQiKSkKCiMgcmVhZCBpbiBmaXRuZXNzCm1jX0dfbG9nLmZpdG5lc3MgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9NQzIvbWNfR19sb2dfZml0bmVzcy5jc3YiKSkKbWNfRy5maXRuZXNzIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvTUMyL21jX0dfZml0bmVzcy5jc3YiKSkKbWNfUl9sb2cuZml0bmVzcyA8LSByZWFkLmNzdihoZXJlKCJkYXRhL01DMi9tY19SX2xvZ19maXRuZXNzLmNzdiIpKQptY19SLmZpdG5lc3MgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9NQzIvbWNfUl9maXRuZXNzLmNzdiIpKQptY19JX2xvZy5maXRuZXNzIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvTUMyL21jX0lfbG9nX2ZpdG5lc3MuY3N2IikpCm1jX0kuZml0bmVzcyA8LSByZWFkLmNzdihoZXJlKCJkYXRhL01DMi9tY19JX2ZpdG5lc3MuY3N2IikpCm1jX0lnX2xvZy5maXRuZXNzIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvTUMyL21jX0lnX2xvZ19maXRuZXNzLmNzdiIpKQptY19JZy5maXRuZXNzIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvTUMyL21jX0lnX2ZpdG5lc3MuY3N2IikpCm1jX0lfSWdfbG9nLmZpdG5lc3MgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9NQzIvbWNfSStJZ19sb2dfZml0bmVzcy5jc3YiKSkKbWNfSV9JZy5maXRuZXNzIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvTUMyL21jX0krSWdfZml0bmVzcy5jc3YiKSkKYGBgCgojIGV4YW1pbmUgdmFyaWF0aW9uCmBgYHtyfQojIHBsb3QgZml0bmVzcyB2cyBpdGVyYXRpb24KZml0bmVzcy5kZiA8LSByYmluZCgKICBjYmluZChtY19HX2xvZy5maXRuZXNzLCBpZCA9ICJHYW1ldG9jeXRlIGxvZzEwIiksCiAgY2JpbmQobWNfRy5maXRuZXNzLCBpZCA9ICJHYW1ldG9jeXRlIiksCiAgY2JpbmQobWNfUl9sb2cuZml0bmVzcywgaWQgPSAiUkJDIGxvZzEwIiksCiAgY2JpbmQobWNfUi5maXRuZXNzLCBpZCA9ICJSQkMiKSwKICBjYmluZChtY19JX2xvZy5maXRuZXNzLCBpZCA9ICJBc2V4dWFsIGlSQkMgbG9nMTAiKSwKICBjYmluZChtY19JLmZpdG5lc3MsIGlkID0gIkFzZXh1YWwgaVJCQyIpLAogIGNiaW5kKG1jX0lnX2xvZy5maXRuZXNzLCBpZCA9ICJTZXh1YWwgaVJCQyBsb2cxMCIpLAogIGNiaW5kKG1jX0lnLmZpdG5lc3MsIGlkID0gIlNleHVhbCBpUkJDIiksCiAgY2JpbmQobWNfSV9JZ19sb2cuZml0bmVzcywgaWQgPSAiQXNleHVhbCAmIHNleHVhbCBpUkJDIGxvZzEwIiksCiAgY2JpbmQobWNfSV9JZy5maXRuZXNzLCBpZCA9ICJBc2V4dWFsICYgc2V4dWFsIGlSQkMiKQopCgojIHF1YW50aWZ5IHZhcmlhbmNlIGFuZCBtZWFuCmZpdG5lc3NfdmFyLmRmIDwtIGZpdG5lc3MuZGYgJT4lIAogIGRwbHlyOjpncm91cF9ieShpZCkgJT4lIAogIGRwbHlyOjpzdW1tYXJpc2UobWVkaWFuID0gbWVkaWFuKG1heF9maXRuZXNzKSwKICAgICAgICAgICAgICAgICAgIG1lYW4gPSBtZWFuKG1heF9maXRuZXNzKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoaWQgPSBmb3JjYXRzOjpmY3RfcmVvcmRlcihpZCwgbWVkaWFuKSkKYGBgCgojIHBsb3QgdmlvbGluIHdpdGggZGlmZmVyZW5jZSBpbiBkZXRlcm1pbmlzdGljIG1vZGVsIGZpdG5lc3MgYW5kIG1lYW4gbW9kZWwgZml0bmVzcwpgYGB7cn0KIyBnZXQgZGV0ZXJtaW5pc3RpYyBkZgpkZXQuZGYgPC0gZGF0YS5mcmFtZShmaXRuZXNzX3Zhci5kZiwgYE1heGltdW0gZml0bmVzc2AgPSAgYyg4LjQ5Nzc3LCA5LjQ5NDk5MSw4Ljg1NDY4Miw5LjU3MzI5MSw4LjU4ODU2LDkuNTYxMzczLDguMjM5OTEsOC4xODE2MDQsOC41NjkyODUsOS42MTg4MTIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShpZCA9IGZvcmNhdHM6OmZjdF9yZW9yZGVyKGlkLCBtZWRpYW4pKSAlPiUgCiAgdGlkeXI6OnBpdm90X2xvbmdlcigtaWQpICU+JSAKICBtdXRhdGUoY2xhc3NpZmljYXRpb24gPSBjYXNlX3doZW4oCiAgICBuYW1lID09ICJNYXhpbXVtLmZpdG5lc3MiIH4iT3B0aW1hbCBzaW5nbGUgaW5mZWN0aW9uIiwKICAgIG5hbWUgPT0gIm1lZGlhbiIgfiJNZWRpYW4gTW9udGUgQ2FybG8iLAogICAgbmFtZSA9PSAibWVhbiIgfiAiTWVhbiBNb250ZSBDYXJsbyIpKQoKbWNfYSA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZGV0LmRmLCBhZXMoeSA9IGlkLCB4ID0gdmFsdWUsIHNoYXBlID0gY2xhc3NpZmljYXRpb24sIGNvbG9yID0gY2xhc3NpZmljYXRpb24pLCBzaXplID0gMywgYWxwaGEgPSAwLjgpICsKICBnZW9tX3Zpb2xpbihkYXRhID0gZml0bmVzcy5kZiwgYWVzKHkgPSBpZCwgeCA9IG1heF9maXRuZXNzKSwgZmlsbCA9ICJ0cmFuc3BhcmVudCIpICsKICBsYWJzKHggPSAiRml0bmVzcyIsIHkgPSAiQ3VlIiwgY29sb3IgPSAiRml0bmVzcyIsIHNoYXBlID0gIkZpdG5lc3MiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImJsYWNrIiwgIiM0NTc1YjQiLCAiI2ZjOGQ1OSIpKQpgYGAKCiMtLS0tLS0tLS0tLS0tLSBwbG90IHRvZ2V0aGVyLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0jCmBgYHtyfQojIGFycmFuZ2UgdGhlIGhlYXQgbWFwCmdnYXJyYW5nZShtY19hLCBtY19wYXJ0aXRpb24sIG5jb2wgPSAyLCBucm93ID0gMSwgbGFiZWxzID0gYygiQSIsICJCIiksIGFsaWduID0gImgiKQoKIyBzYXZlCmdnc2F2ZSh1bml0cyA9ICJweCIsIGRwaSA9IDMwMCwgd2lkdGggPSAyMTAwLCBoZWlnaHQgPSAxNDAwLCBmaWxlbmFtZSA9IGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vTUMudGlmZiIpLCBiZyA9ICJ3aGl0ZSIsIHNjYWxlID0gMS41KQpgYGAKCgojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0jCiMgZHVhbCBjdWUgb3B0aW1pemF0aW9uIGZpZ3VyZQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0jCmBgYHtyfQpzb3VyY2UoaGVyZSgiZnVuY3Rpb25zL2NoYWJhdWRpX3NpX2NsZWFuX2hpZ2guUiIpKQpzb3VyY2UoaGVyZSgiZnVuY3Rpb25zL2NoYWJhdWRpX3NpX2NsZWFuLlIiKSkKc291cmNlKGhlcmUoImZ1bmN0aW9ucy9wYXJfdG9faG1fdGUuUiIpKQpgYGAKCiMtLS0tLS0tLS0tIHBsb3R0aW5nIGZpdG5lc3Mgb2YgZHVhbCB2cyBzaW5nbGUgY3VlIG9wdCAtLS0tLS0tLS0jCiMgaW1wb3J0IGluIHByZXZpb3VzIGRhdGEKYGBge3J9CiMgZHVhbCBjdWUgZml0bmVzcwpkdWFsX2ZpdG5lc3MuZGYgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9kdWFsX2N1ZV9vcHQ0L2R1YWxfY3VlX2ZpdG5lc3NfMjAuY3N2IikpCiMjIG1ha2UgbGFiZWwgYW5kIGZpbHRlciBvdXQgdmVyeSBsb3cgZml0bmVzcwpkdWFsX2ZpdG5lc3MuZGYgPC0gZHVhbF9maXRuZXNzLmRmICU+JSAKICBtdXRhdGUodGVtcF9sYWJlbCA9IGdzdWIoImxvZyIsICJsb2cxMCIsIGxhYmVsKSwKICAgICAgICAgdGVtcF9sYWJlbF9iID0gZ3N1YigibG9nIiwgImxvZzEwIiwgbGFiZWxfYiksCiAgICAgICAgIGxhYmVsX2ZpbmFsID0gcGFzdGUwKHRlbXBfbGFiZWwsICIrIiwgdGVtcF9sYWJlbF9iKSkgJT4lIAogIGZpbHRlcih2YWx1ZSA+IDIpCgojIGdldCBzaW5nbGUgY3VlIGZpdG5lc3MKc2lfZHluLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL3NpX2R5bi9zaV9keW5fMzAucGFycXVldCIpKSAKc2lfZml0bmVzcy5kZiA8LSBzaV9keW4uZGYgJT4lIAogIGZpbHRlcih2YXJpYWJsZSA9PSAidGF1X2N1bSIgJiB0aW1lID09IDIwKQoKIyBqb2luIHNpIGFuZCBkdWFsIGN1ZQpkdWFsX3NpX2ZpdG5lc3MuZGYgPC0gZHVhbF9maXRuZXNzLmRmICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KHNpX2ZpdG5lc3MuZGYsIGlkLCBzaV9maXRuZXNzID0gdmFsdWUpLCBieSA9ICJpZCIpICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KHNpX2ZpdG5lc3MuZGYsIGlkX2IgPSBpZCwgc2lfZml0bmVzc19iID0gdmFsdWUpLCBieSA9ICJpZF9iIikgJT4lIAogIG11dGF0ZShzaV9maXRuZXNzX21heCA9IGlmZWxzZShzaV9maXRuZXNzID4gc2lfZml0bmVzc19iLCBzaV9maXRuZXNzLCBzaV9maXRuZXNzX2IpLAogICAgICAgICBkdWFsX2xhYmVsID0gZ3N1YigibG9nIiwgImxvZzEwIiwgcGFzdGUobGFiZWwsICIrIiwgbGFiZWxfYikpKQpgYGAKCiMgcGxvdApgYGB7cn0KZHVhbF9zaV9maXRuZXNzLnBsIDwtIGdncGxvdCgpICsKICBnZW9tX3BvaW50KGRhdGEgPSBkdWFsX3NpX2ZpdG5lc3MuZGYsIGFlcyh5ID0gZm9yY2F0czo6ZmN0X3Jlb3JkZXIoZHVhbF9sYWJlbCwgdmFsdWUpLCB4ID0gdmFsdWUsIGNvbG9yID0gIkR1YWwgY3VlIiwgc2hhcGUgPSAiRHVhbCBjdWUiKSwgc2l6ZSA9IDMsIGFscGhhID0gMC43KSArCiAgZ2VvbV9wb2ludChkYXRhID0gZHVhbF9zaV9maXRuZXNzLmRmLCBhZXMoeSA9IGZvcmNhdHM6OmZjdF9yZW9yZGVyKGR1YWxfbGFiZWwsIHZhbHVlKSwgeCA9IHNpX2ZpdG5lc3NfbWF4LCBjb2xvcj0gIkJlc3Qgc2luZ2xlIGN1ZSIsIHNoYXBlPSAiQmVzdCBzaW5nbGUgY3VlIiksIHNpemUgPSAzLCBhbHBoYSA9IDAuNykgKwogIGxhYnMoeCA9ICJGaXRuZXNzIiwgeSA9ICJEdWFsIGN1ZSIsIGNvbG9yID0gIkN1ZSIsIHNoYXBlID0gIkN1ZSIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIiNmYzhkNTkiLCAiIzQ1NzViNCIpKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gOS44ODM2MDIpICsKICBnZW9tX3RleHQoYWVzKHg9OS44ODM2MDIsIGxhYmVsPSJcblRpbWUtYmFzZWQgZml0bmVzcyAoZGY9OSkiLCB5ID0gIkcgKyBSIGxvZzEwIiksIGFuZ2xlPTkwKSArCiAgeGxpbSg4LjM1LCAxMCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpgYGAKCgojLS0tLS0tLS0tLS0gdGltZSBzZXJpZXMgY29udmVyc2lvbiByYXRlIC0tLS0tLS0tLS0tLS0jCiMgZHluYW1pY3Mgc2ltdWxhdGlvbiBvZiBoaWdoIHBhcmFtZXRlciBjdWVzICh0aGVzZSBzZXJ2ZSBhcyByZWZlcmVuY2UgcG9pbnRzKQpgYGB7cn0KIyBiZXN0IGR1YWwgY3VlIGNvbWJvCmR1YWwuY3IgPC0gY2hhYmF1ZGlfc2lfY2xlYW4oCiAgcGFyYW1ldGVyc19jciA9IGMoNC40NDYxOTIwMzMsCTEwLjk3NTE4Mjc1LAkxLjM4NzYyODE3LAkyMy4zMDU5MjU0LAktMy40NTIwNTIzNzEsCS0xOC4wMDcwNjkyLAkzOS42NjYxNDIyNiwJLTMuNTQ1MTkzMTQxLAkxOC43ODM1MDc5OSksCiAgaW1tdW5pdHkgPSAidHN1a3VzaGkiLAogIHBhcmFtZXRlcnMgPSBwYXJhbWV0ZXJzX3RzdWt1c2hpLAogIHRpbWVfcmFuZ2UgPSBzZXEoMCwgMjAsIGJ5ID0gMWUtMyksCiAgY3VlX3JhbmdlID0gIHNlcSg2LCA3LCBieSA9IDEvNTAwKSwKICBjdWVfcmFuZ2VfYiA9IHNlcSgwLCBsb2cxMCg2KigxMF42KSksIGJ5ID0gKGxvZzEwKDYqKDEwXjYpKSkvNTAwKSwKICBjdWUgPSAiUiIsCiAgY3VlX2IgPSAiSSIsCiAgbG9nX2N1ZSA9ICJsb2cxMCIsCiAgbG9nX2N1ZV9iID0gImxvZzEwIiwKICBzb2x2ZXIgPSAidm9kZSIsCiAgZHluID0gVAopCgojIHdoZW4gdGltZSBpcyB1c2VkIGFzIGEgY3VlIChoaWdoIHBhcmFtZXRlcikKdGltZS5jciA8LSBjaGFiYXVkaV9zaV9jbGVhbl9oaWdoKAogIHBhcmFtZXRlcnNfY3IgPSBjKDkuMTU0MzE0LCAgLTcuNTcwODI5LCAtMjIuNTA2NjM4ICwgIDMuMzgyNDA1ICwtMTMuNDUzNTE5ICwtMTcuMDExNDg1ICAsIDMuNjc4MTgxLCAtMTIuODUxODk1ICwtMjYuMTE1MTU4KSwKICBpbW11bml0eSA9ICJ0c3VrdXNoaSIsCiAgcGFyYW1ldGVycyA9IHBhcmFtZXRlcnNfdHN1a3VzaGksCiAgdGltZV9yYW5nZSA9IHNlcSgwLCAyMCwgYnkgPSAxZS0zKSwKICBjdWVfcmFuZ2UgPSAgc2VxKDAsIDIwLCBieSA9IDFlLTMpLAogIGN1ZSA9ICJ0IiwKICBzb2x2ZXIgPSAidm9kZSIsCiAgZHluID0gVCkKCiMgd2hlbiBhc2V4dWFsIGlSQkMgaXMgdXNlZCBhcyBhIGN1ZSAoaGlnaCBmbGV4aWJpbGl0eSkKSV9oaWdoLmNyIDwtIGNoYWJhdWRpX3NpX2NsZWFuX2hpZ2goCiAgcGFyYW1ldGVyc19jciA9IGMoMS4yOTY2NzUsICAzLjU0NDAzNCAsIDQuOTA3NDg0LCAgMi4xNzQyNDksIC0zLjIzODMwOSAsLTUuMTgxNjE0ICwtMS42NDUwNzIgLCAxLjgzNDMwMiAsIDEuNTgxMDExKSwKICBpbW11bml0eSA9ICJ0c3VrdXNoaSIsCiAgcGFyYW1ldGVycyA9IHBhcmFtZXRlcnNfdHN1a3VzaGksCiAgdGltZV9yYW5nZSA9IHNlcSgwLCAyMCwgYnkgPSAxZS0zKSwKICBjdWVfcmFuZ2UgPSAgc2VxKDAsIGxvZzEwKDYqKDEwXjYpKSwgYnkgPSAobG9nMTAoNiooMTBeNikpKS81MDAwKSwKICBjdWUgPSAiSSIsCiAgbG9nX2N1ZSA9ICJsb2cxMCIsCiAgc29sdmVyID0gInZvZGUiLAogIGR5biA9IFQpCgojIHdoZW4gYXNleHVhbCBpUkJDIGlzIHVzZWQgYXMgYSBjdWUgKG5vcm1hbCBmbGV4aWJpbGl0eSkKSS5jciA8LSBjaGFiYXVkaV9zaV9jbGVhbigKICBwYXJhbWV0ZXJzX2NyID0gYyg1LjQ2MzU1OCwJMi4zODM5NDgsCS0xNy43NTcyODEsCTQuNTcxODM1KSwKICBpbW11bml0eSA9ICJ0c3VrdXNoaSIsCiAgcGFyYW1ldGVycyA9IHBhcmFtZXRlcnNfdHN1a3VzaGksCiAgdGltZV9yYW5nZSA9IHNlcSgwLCAyMCwgYnkgPSAxZS0zKSwKICBjdWVfcmFuZ2UgPSAgc2VxKDAsIGxvZzEwKDYqKDEwXjYpKSwgYnkgPSAobG9nMTAoNiooMTBeNikpKS81MDAwKSwKICBjdWUgPSAiSSIsCiAgbG9nX2N1ZSA9ICJsb2cxMCIsCiAgc29sdmVyID0gInZvZGUiLAogIGR5biA9IFQpCgojIHdoZW4gUkJDIGlzIHVzZWQgYXMgY3VlIChoaWdoIGZsZXhpYmlsaXR5KQpSX2hpZ2guY3IgPC0gY2hhYmF1ZGlfc2lfY2xlYW5faGlnaCgKICBwYXJhbWV0ZXJzX2NyID0gYyg1LjAzNDAzNDggLCAgMC41ODQ2MTY4ICwgIDAuMzc0OTY0OCAsICAwLjY4NDI2NzMgICwgMi40NzQ4MTA3ICwgMTAuOTAzNjAzNCAsIDE2LjgyNDYzMTYsIC0yNC44NjkwOTcxICwxLjgwMDcyMzgpLAogIGltbXVuaXR5ID0gInRzdWt1c2hpIiwKICBwYXJhbWV0ZXJzID0gcGFyYW1ldGVyc190c3VrdXNoaSwKICB0aW1lX3JhbmdlID0gc2VxKDAsIDIwLCBieSA9IDFlLTMpLAogIGN1ZV9yYW5nZSA9ICBzZXEobG9nMTAoMTBeNiksIGxvZzEwKDEwXjcpLCBieSA9IChsb2cxMCgxMF43KS1sb2cxMCgxMF42KSkvNTAwMCksCiAgY3VlID0gIlIiLAogIGxvZ19jdWUgPSAibG9nMTAiLAogIHNvbHZlciA9ICJ2b2RlIiwKICBkeW4gPSBUKQoKIyBwcm9jZXNzIApJX2hpZ2guY3IyIDwtIElfaGlnaC5jciAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJjciIpICU+JSBtdXRhdGUobGFiZWxfbmV3ID0gIkkgbG9nMTAgKGRmPTkpIikgJT4lIHNlbGVjdCgtdmFyaWFibGUpCgpSX2hpZ2guY3IyIDwtIFJfaGlnaC5jciAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJjciIpICU+JSBtdXRhdGUobGFiZWxfbmV3ID0gIlIgbG9nMTAgKGRmPTkpIikgJT4lIHNlbGVjdCgtdmFyaWFibGUpCgp0aW1lX2hpZ2guY3IyIDwtIHRpbWUuY3IgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiY3IiKSAlPiUgbXV0YXRlKGxhYmVsX25ldyA9ICJUaW1lIChkZj05KSIpICU+JSBzZWxlY3QoLXZhcmlhYmxlKQoKZHVhbC5jcjIgPC0gZHVhbC5jciAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJjciIpICU+JSBtdXRhdGUobGFiZWxfbmV3ID0gIlIgbG9nMTArSSBsb2cxMFxuKGRmPTkpIikgJT4lIHNlbGVjdCgtdmFyaWFibGUpCgojIGNvbWJpbmUKZHVhbF9jci5kZiA8LSByYmluZChJX2hpZ2guY3IyLCBSX2hpZ2guY3IyLCB0aW1lX2hpZ2guY3IyLCBkdWFsLmNyMikKYGBgCgojIHBsb3QKYGBge3J9CmR1YWxfY3IucGwgPC0gZ2dwbG90KCkgKwogIGdlb21fbGluZShkYXRhID0gZHVhbF9jci5kZiwgYWVzKGNvbG9yID0gbGFiZWxfbmV3LCB4ID0gdGltZSwgeSA9IHZhbHVlKSwgc2l6ZSA9IDEpICsKICBnZW9tX3BvaW50KGRhdGEgPSBkdWFsX2NyLmRmICU+JSBmaWx0ZXIodGltZSUlMSA9PSAwKSwgYWVzKGNvbG9yID0gbGFiZWxfbmV3LCB4ID0gdGltZSwgeSA9IHZhbHVlLCBzaGFwZSA9IGxhYmVsX25ldyksIHNpemUgPSAzKSArCiAgbGFicyh4ID0gIlRpbWUgKGRheXMpIiwgeSA9ICJDb252ZXJzaW9uIHJhdGUiLCBjb2xvciA9ICJDdWUiLCBzaGFwZSA9ICJDdWUiKSArCiAgeGxpbSgwLCAyMCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjZmM4ZDU5IiwiI2ZkY2I0NCIsImJsYWNrIiwgIiM0NTc1YjQiKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0icmlnaHQiLAogICAgICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKHQgPSA0MCwgciA9IDAsIGIgPSAwLCBsID0gMCwgdW5pdCA9ICJwdCIpKSArCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSA0LCBieXJvdyA9IFRSVUUpKQpgYGAKCiMtLS0tLS0tLS0tLS0gcmVhY3Rpb24gbm9ybSBoZWF0bWFwIG9mIFIgbG9nMTAgKyBJIGxvZzEwIC0tLS0tLS0tLS0tLSMKIyBwcm9jZXNzIGRhdGEKYGBge3J9CiMgbWFrZSBoZWF0bWFwIGRmClJfSS5obSA8LSBwYXJfdG9faG1fdGUocGFyID0gYyg0LjQ0NjE5MjAzMywJMTAuOTc1MTgyNzUsCTEuMzg3NjI4MTcsCTIzLjMwNTkyNTQsCS0zLjQ1MjA1MjM3MSwJLTE4LjAwNzA2OTIsCTM5LjY2NjE0MjI2LAktMy41NDUxOTMxNDEsCTE4Ljc4MzUwNzk5KSwKICAgICAgICAgICAgIGN1ZV9yYW5nZSA9IHNlcSg2LAk3LCBsZW5ndGgub3V0ID0gNTAwKSwKICAgICAgICAgICAgIGN1ZV9yYW5nZV9iID0gc2VxKDAsCTYuNzc4MTUxMjUsIGxlbmd0aC5vdXQgPSA1MDApKQoKIyBwcm9jZXNzIGR5bmFtaWNzClJfSS5keW4gPC0gZHVhbC5jciAlPiUgCiAgdGlkeXI6OnBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSB2YXJpYWJsZSwgdmFsdWVzX2Zyb20gPSB2YWx1ZSkgJT4lIAogIG11dGF0ZShsb2dfUiA9IGxvZzEwKFIpLAogICAgICAgICBsb2dfSSA9IGxvZzEwKEkpKQoKIyBleGFtaW5lIHNleHVhbCBpUkJDIGFzIHdlbGwKUl9JZy5keW4gPC0gZHVhbC5jciAlPiUgCiAgdGlkeXI6OnBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSB2YXJpYWJsZSwgdmFsdWVzX2Zyb20gPSB2YWx1ZSkgJT4lIAogIG11dGF0ZShsb2dfUiA9IGxvZzEwKFIpLAogICAgICAgICBsb2dfSWcgPSBsb2cxMChJZykpCm1heChSX0lnLmR5biRJZykgCmBgYAoKIyBwbG90CmBgYHtyfQpkdWFsX3JuLnBsIDwtIGdncGxvdCgpICsKICBnZW9tX3Jhc3RlcihkYXRhID0gUl9JLmhtLCBhZXMoeCA9IGN1ZV9yYW5nZV9iLCB5ID0gY3VlX3JhbmdlLCBmaWxsID0gY3IpKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2MoKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBSX0kuZHluLCBhZXMoeCA9IGxvZ19JLCB5ID0gbG9nX1IpLCBjb2xvciA9ICJ3aGl0ZSIsIGFycm93ID0gYXJyb3coYW5nbGUgPSAzMCwgbGVuZ3RoID0gdW5pdCgwLjEsICJpbmNoZXMiKSkpICsKICBnZW9tX3BvaW50KGRhdGEgPSBSX0kuZHluICU+JSBmaWx0ZXIocm93X251bWJlcigpICUlIDEwMDAgPT0gMSAmIHRpbWUgPD0gMjApLCBhZXMoeCA9IGxvZ19JLCB5ID0gbG9nX1IpLCBjb2xvciA9ICJ3aGl0ZSIpICsKICB4bGltKDAuOTkqbWluKGhhYmxhcjo6cyhSX0kuZHluJGxvZ19JKSwgbmEucm0gPSBUKSwgMS4wMSogbWF4KGhhYmxhcjo6cyhSX0kuZHluJGxvZ19JKSwgbmEucm0gPSBUKSkgKwogIHlsaW0oMC45OSptaW4oaGFibGFyOjpzKFJfSS5keW4kbG9nX1IpLCBuYS5ybSA9IFQpLDEuMDEqIG1heChoYWJsYXI6OnMoUl9JLmR5biRsb2dfUiksIG5hLnJtID0gVCkpICsKICBsYWJzKHkgPSAiUkJDIGxvZzEwIiwgeCA9ICJBc2V4dWFsIGlSQkMgbG9nMTAiLCBmaWxsID0gIkNvbnZlcnNpb25cbnJhdGUiKSArCiAgdGhlbWVfZGFyaygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKQoKIyBqdXN0IHRlc3RpbmcgZm9yIHNleHVhbCBpUkJDIHZzIFJCQwpnZ3Bsb3QoKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBSX0lnLmR5biwgYWVzKHggPSBJZywgeSA9IGxvZ19SKSwgY29sb3IgPSAid2hpdGUiLCBhcnJvdyA9IGFycm93KGFuZ2xlID0gMzAsIGxlbmd0aCA9IHVuaXQoMC4xLCAiaW5jaGVzIikpKSArCiAgZ2VvbV9wb2ludChkYXRhID0gUl9JZy5keW4gJT4lIGZpbHRlcihyb3dfbnVtYmVyKCkgJSUgMTAwMCA9PSAxICYgdGltZSA8PSAyMCksIGFlcyh4ID0gSWcsIHkgPSBsb2dfUiksIGNvbG9yID0gIndoaXRlIikgKwogIHNjYWxlX3hfY29udGludW91cyh0cmFucyA9ICJsb2cxMCIpICsKICB4bGltKDAsIDIwMDAwMCkgKwogIGxhYnMoeSA9ICJSQkMgbG9nMTAiLCB4ID0gIlNleHVhbCBpUkJDIGxvZzEwIiwgZmlsbCA9ICJDb252ZXJzaW9uIHJhdGUiKSArCiAgdGhlbWVfZGFyaygpCmBgYAoKIyBzYXZlIGZpZ3VyZSBmb3IgcG9zdGVyCmBgYHtyfQpkdWFsX3JuLnBsMiA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9yYXN0ZXIoZGF0YSA9IFJfSS5obSwgYWVzKHggPSBjdWVfcmFuZ2VfYiwgeSA9IGN1ZV9yYW5nZSwgZmlsbCA9IGNyKSkgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKCkgKwogIGdlb21fcGF0aChkYXRhID0gUl9JLmR5biwgYWVzKHggPSBsb2dfSSwgeSA9IGxvZ19SKSwgY29sb3IgPSAid2hpdGUiLCBhcnJvdyA9IGFycm93KGFuZ2xlID0gMzAsIGxlbmd0aCA9IHVuaXQoMC4xLCAiaW5jaGVzIikpKSArCiAgZ2VvbV9wb2ludChkYXRhID0gUl9JLmR5biAlPiUgZmlsdGVyKHJvd19udW1iZXIoKSAlJSAxMDAwID09IDEgJiB0aW1lIDw9IDIwKSwgYWVzKHggPSBsb2dfSSwgeSA9IGxvZ19SKSwgY29sb3IgPSAid2hpdGUiKSArCiAgeGxpbSgwLjk5Km1pbihoYWJsYXI6OnMoUl9JLmR5biRsb2dfSSksIG5hLnJtID0gVCksIDEuMDEqIG1heChoYWJsYXI6OnMoUl9JLmR5biRsb2dfSSksIG5hLnJtID0gVCkpICsKICB5bGltKDAuOTkqbWluKGhhYmxhcjo6cyhSX0kuZHluJGxvZ19SKSwgbmEucm0gPSBUKSwxLjAxKiBtYXgoaGFibGFyOjpzKFJfSS5keW4kbG9nX1IpLCBuYS5ybSA9IFQpKSArCiAgbGFicyh5ID0gIlJCQyBsb2cxMCIsIHggPSAiQXNleHVhbCBpUkJDIGxvZzEwIiwgZmlsbCA9ICJDb252ZXJzaW9uIHJhdGUiKSArCiAgdGhlbWVfZGFyaygpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKSAKCmR1YWxfY3IucGwyIDwtIGdncGxvdCgpICsKICBnZW9tX2xpbmUoZGF0YSA9IGR1YWxfY3IuZGYsIGFlcyhjb2xvciA9IGxhYmVsX25ldywgeCA9IHRpbWUsIHkgPSB2YWx1ZSksIHNpemUgPSAxKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZHVhbF9jci5kZiAlPiUgZmlsdGVyKHRpbWUlJTEgPT0gMCksIGFlcyhjb2xvciA9IGxhYmVsX25ldywgeCA9IHRpbWUsIHkgPSB2YWx1ZSwgc2hhcGUgPSBsYWJlbF9uZXcpLCBzaXplID0gMikgKwogIGxhYnMoeCA9ICJUaW1lIChkYXlzKSIsIHkgPSAiQ29udmVyc2lvbiByYXRlIiwgY29sb3IgPSAiQ3VlIiwgc2hhcGUgPSAiQ3VlIikgKwogIHhsaW0oMCwgMjApICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiIzQ1NzViNCIsICIjOTFiZmRiIiwiI2ZjOGQ1OSIsIiNmZGNiNDQiKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0idG9wIikgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMiwgYnlyb3cgPSBUUlVFKSkKCmdnYXJyYW5nZShkdWFsX2NyLnBsMiwgZHVhbF9ybi5wbDIsIGFsaWduID0gImgiLCB3aWR0aHMgPSBjKDEuMjUsIDEpKQpnZ3NhdmUoaGVyZSgicG9zdGVyL2R1YWxfY3VlLnBuZyIpLCB3aWR0aCA9IDcsIGhlaWdodCA9IDQpCmBgYAoKCiMtLS0tLS0tLSBhc3NlbWJsZSBmaW5hbCBmaWd1cmUgLS0tLS0tLS0tLS0tLSMKYGBge3J9CiMgYXNzZW1ibGUgcGFuZWwgQiBhbmQgQwpkdWFsX3BsLkJDIDwtIGdnYXJyYW5nZShkdWFsX2NyLnBsLCBkdWFsX3JuLnBsLCBhbGlnbiA9ICJ2IiwgbmNvbCA9IDEsIGxhYmVscyA9IGMoIkIiLCAiQyIpKQoKIyBhc3NlbWJsZSBwYW5lbCBBCmdnYXJyYW5nZShkdWFsX3NpX2ZpdG5lc3MucGwsIGR1YWxfcGwuQkMsIG5jb2wgPSAyLCBsYWJlbHMgPSBjKCJBIiwgIiIpLCB3aWR0aHMgPSBjKDEsMS4xKSkKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vZHVhbF9jdWUudGlmZiIpLCB1bml0cyA9ICJweCIsIHdpZHRoID0gMjEwMCwgaGVpZ2h0ID0gMTQwMCwgc2NhbGUgPSAxLjMsIGRwaT0zMDAsICBiZyA9ICJ3aGl0ZSIpCmBgYAoKCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIyBkeW5hbWljcyBvZiBkdWFsIGN1ZSBzaW11bGF0aW9uIChhbGwgY29tYmluYXRpb25zKQojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMgY29udmVyc2lvbiByYXRlCmBgYHtyfQojIGltcG9ydCBpbiBkdWFsIGN1ZSBkeW5hbWljcwpkdWFsX2R5bi5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9kdWFsX2N1ZV9keW4vZHVhbF9jdWVfZHluLnBhcnF1ZXQiKSkKCiMga2VlcCBvbmx5IGNyIGFuZCBtYWtlIGxhYmVscyBmb3IgcGxvdHRpbmcuIHdlIGFyZSBnb2luZyB0byBvbWl0IGFueSBjdWUgY29tYmluYXRpb25zIGNvbnRhaW5pbmcgSStJZyBkdWUgdG8gdGhvc2Ugbm90IG9wdGltaXppbmcgYXQgYWxsCmR1YWxfY3IuZGZfcCA8LSBkdWFsX2R5bi5kZiAlPiUgCiAgZmlsdGVyKHZhcmlhYmxlID09ICJjciIgJiBjdWUgIT0gIkkrSWciICYgY3VlX2IgIT0gIkkrSWciKSAlPiUgCiAgbXV0YXRlKGxhYmVsX3Bsb3QgPSBwYXN0ZShsYWJlbCwgIisiLCBsYWJlbF9iKSkgJT4lIAogIGdyb3VwX2J5KGxhYmVsX3Bsb3QpICU+JSAKICBhcnJhbmdlKHRpbWUsIC5ieV9ncm91cCA9IFQpICU+JSAKICBmaWx0ZXIocm93X251bWJlcigpICUlIDEwID09IDEpICU+JSAgIyBjdXQgZG93biBvbiBudW1iZXIgb2Ygcm93cwogIGxlZnRfam9pbihzZWxlY3QoZHVhbF9maXRuZXNzLmRmLCBpZCwgaWRfYiwgZml0bmVzcyA9IHZhbHVlKSwgYnkgPSBjKCJpZCIsICJpZF9iIikpICMgZ2V0IGZpdG5lc3MKCiMgcGxvdCByYXN0ZXIKZ2dwbG90KGRhdGEgPSBkdWFsX2NyLmRmX3AsIGFlcyh4ID0gdGltZSwgeSA9IGZjdF9yZW9yZGVyKGxhYmVsX3Bsb3QsIGZpdG5lc3MpLCBmaWxsID0gdmFsdWUpKSArCiAgZ2VvbV9yYXN0ZXIoKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2MoKSArCiAgeGxpbSgxLCAyMCkgKwogIGxhYnMoeCA9ICJUaW1lIChkYXlzKSIsIHkgPSAiRHVhbCBjdWUgY29tYmluYXRpb24iLCBmaWxsID0gIkNvbnZlcnNpb24gcmF0ZSIpICsKICB0aGVtZV9idygpCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby9kdWFsX2N1ZV9jci50aWZmIiksIHVuaXRzID0gInB4Iiwgd2lkdGggPSAyMDAwLCBoZWlnaHQgPSAxNTAwLCBkcGk9MzAwLCAgYmcgPSAid2hpdGUiKQpgYGAKCiMgY3VtdWx0YXRpdmUgdHJhbnNtaXNzaW9uIHRyYW5zbWlzc2lvbiBwb3RlbnRpYWwKUHJvdmluZyBhIHBvaW50IHRvIG15c2VsZgpgYGB7cn0KZHVhbF90YXUuZGZfcCA8LSBkdWFsX2R5bi5kZiAlPiUgCiAgZmlsdGVyKHZhcmlhYmxlID09ICJ0YXVfY3VtIiAmIGN1ZSAhPSAiSStJZyIgJiBjdWVfYiAhPSAiSStJZyIpICU+JSAKICBtdXRhdGUobGFiZWxfcGxvdCA9IHBhc3RlKGxhYmVsLCAiKyIsIGxhYmVsX2IpKSAlPiUgCiAgZ3JvdXBfYnkobGFiZWxfcGxvdCkgJT4lIAogIGFycmFuZ2UodGltZSwgLmJ5X2dyb3VwID0gVCkgJT4lIAogIGZpbHRlcihyb3dfbnVtYmVyKCkgJSUgMTAgPT0gMSkgJT4lICAjIGN1dCBkb3duIG9uIG51bWJlciBvZiByb3dzCiAgbGVmdF9qb2luKHNlbGVjdChkdWFsX2ZpdG5lc3MuZGYsIGlkLCBpZF9iLCBmaXRuZXNzID0gdmFsdWUpLCBieSA9IGMoImlkIiwgImlkX2IiKSkgJT4lICAjIGdldCBmaXRuZXNzIAogIGZpbHRlcihmaXRuZXNzID4gOS42NSkKCiMgaXQgc2VlbXMgdGhhdCBSIGxvZytJIGxvZyBvbmx5IGluY2hlcyBhaGVhZCBvZiBvdGhlciBhdCB0aGUgdmVyeSBlbmQgb2YgdGhlIGluZmVjdGlvbiwgc3VnZ2VzdGluZyB0aGF0IHRlcm1pbmFsIGludmVzdG1lbnQgaXMgYXQgcGxheQpnZ3Bsb3QoZGF0YSA9IGR1YWxfdGF1LmRmX3AsIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlLCBjb2xvciA9IGxhYmVsX3Bsb3QpKSArCiAgZ2VvbV9saW5lKCkgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKCkgKwogIHhsaW0oMTUsIDIwKSArCiAgeWxpbSg1LDEwKSArCiAgbGFicyh4ID0gIlRpbWUgKGRheXMpIiwgeSA9ICJEdWFsIGN1ZSBjb21iaW5hdGlvbiIsIGZpbGwgPSAiQ29udmVyc2lvbiByYXRlIikgKwogIHRoZW1lX2J3KCkKYGBgCgoKCgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMgZ2V0IGR1YWwgY3VlIGRpc2Vhc2UgbWFwIChzaW11bGF0ZWQpCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKSSBhbSBnb2luZyB0byB0YWtlIHRoZSBvcHRpbWFsIGR5bmFtaWMgKFIgbG9nMTAgKyBJIGxvZzEwKSBhbmQgcGxvdCBhbGwgcG9zc2libGUgZGlzZWFzZSBjdXJ2ZXMgYW5kIHNlZSBpZiBhbnkgZm9sbG93IHRoZSBoeXN0ZXJlc2lzIGN1cnZlLiBTZWUgYmVsb3cgZm9yIHJlYWwgbGlmZSBkaXNlYXNlIGN1cnZlLgoKIyBwcm9jZXNzIApgYGB7cn0KIyBnZXQgbGlzdCBvZiBpbnRlcmVzdGVkIHZhcmlhYmxlcyBmb3IgcGxvdHRpbmcuIGRyb3AgY3IsIGZpdG5lc3MsIGFuZCBkZWF0aCBwcm9iYWJpbGl0eSwgaW1tdW5pdHksIGFuZCBtZXJvem9pdGVzICh3aGljaCBpcyBub3Qgb3B0aW1pemVkIGluIGR1YWwgY3VlKQpkdWFsX3Zhci5scyA8LSB1bmlxdWUoZHVhbC5jciR2YXJpYWJsZSlbIXVuaXF1ZShkdWFsLmNyJHZhcmlhYmxlKSAlaW4lIGMoInRhdSIsICJ0YXVfY3VtIiwgImNyIiwgImNyX3QiLCAiSUQiLCAiTiIsICJXIiwgIk0iLCAiTWciKV0KCiMgY3JlYXRlIGFsbCBwb3NzaWJsZSB2YXJpYWJsZSBjb21iaW5hdGlvbnMuIDYgdmFyaWFibGUgY29tYmluYXRpb24gKDQqNCB3aXRoIDQgc2FtZSByZWR1bmRhbnQgYW5kIGhhbGYgb2YgdGhhdCkgaXMgZXhwZWN0ZWQKZHVhbF92YXIuY29tYiA8LSB0aWR5cjo6ZXhwYW5kX2dyaWQoeCA9IGR1YWxfdmFyLmxzLAogICAgICAgICAgICAgICAgICAgICAgeSA9IGR1YWxfdmFyLmxzKSAlPiUgCiAgZmlsdGVyKHggIT0geSkgJT4lIAogIG11dGF0ZSh0bXAgPSBwYXN0ZTAocG1pbih4LCB5KSwgcG1heCh4LCB5KSkpICU+JSAjIGVsaW1pbmF0ZSBzYW1lIHZhcmlhYmxlIGJ1dCBkaWZmZXJlbnQgb3JkZXIKICBzbGljZV9oZWFkKG4gPSAxLCBieSA9IHRtcCkgJT4lIAogIHNlbGVjdCgtdG1wKQoKZHVhbF92YXIuY29tYgoKIyBmaWx0ZXIgb3V0IGludGVybWVkaWF0ZSBkYXRhIHBvaW50cyBpbiBkeW5hbWljIHNvIHdlIGNvdWxkIGhhdmUgZmFzdGVyIHBsb3R0aW5nLiBBbHNvIG1ha2Ugd2lkZXIgZm9yIHBsb3R0aW5nCiMjIGZpbHRlcmluZyBvdXQgYWxsIChub25lIGNyIHZhcmlhYmxlKSB2YWx1ZSBiZWxvdyAxIHNvIG5lZ2F0aXZlIHZsdWVzIGRvIG5vdCBvdmVyd2hlbG0gZGlzZWFzZSBjdXJ2ZS4gRm9yIGNyLCBrZWVwIG9ubHkgdmFsdWUgYmVsb3cgb3IgZXF1YWwgdG8gMQpkdWFsX2NyLmYgPC0gZHVhbC5jciAlPiUgCiAgZmlsdGVyKHZhcmlhYmxlICVpbiUgYyhkdWFsX3Zhci5scywgImNyIikgJiBjYXNlX3doZW4odmFyaWFibGUgIT0gImNyIiB+IHZhbHVlID4gMSwgVH4gdmFsdWUgPD0xKSkgJT4lIAogIHRpZHlyOjpwaXZvdF93aWRlcihuYW1lc19mcm9tID0gdmFyaWFibGUsIGlkX2NvbHMgPSBjKHRpbWUpKSAlPiUgCiAgYXJyYW5nZSh0aW1lKSAlPiUgCiAgZmlsdGVyKHJvd19udW1iZXIoKSAlJSAxMDAgPT0gMSkgCgpgYGAKCiMgcGxvdApgYGB7cn0KIyBtYWtlIHBhdGggcGxvdAojIyBubyBsb2dnZWQgb24geCBhbmQgeQpkdWFsX2N1cnZlLnBsIDwtIHB1cnJyOjptYXAyKC54ID0gZHVhbF92YXIuY29tYiR4LCAKICAgICAueSA9IGR1YWxfdmFyLmNvbWIkeSwKICAgICAgfntnZ3Bsb3QoKSArCiAgICAgICAgICBnZW9tX3BhdGgoZGF0YSA9IGR1YWxfY3IuZiwgYWVzX3N0cmluZyh4ID0gLnksIHkgPSAueCwgY29sb3IgPSAiY3IiKSwKICAgICAgICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoYyhyZXAoMCwgbnJvdyhkdWFsX2NyLmYpIC0gMiksIDAuMjUpLCAiaW5jaGVzIikpLAogICAgICAgICAgICAgICAgICAgIHNpemUgPSAxKSArCiAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBkdWFsX2NyLmYgJT4lIGZpbHRlcihyb3dfbnVtYmVyKCkgJSUgMTAgPT0xKSwgCiAgICAgICAgICAgICAgICAgICAgIGFlc19zdHJpbmcoeCA9IC55LCB5ID0gLngsIGNvbG9yID0gImNyIiksIHNpemUgPSAzKSArCiAgICAgICAgICBsYWJzKGNvbG9yID0gIkNvbnZlcnNpb24gcmF0ZSIpICsgIyBub3RlIHRoZSBsYWJlbHMgYXJlIHJldmVyc2VkIGJlY2F1c2Ugd2Ugc2V0IHg9IHkgYW5kIHkgPSB4IGFib3ZlCiAgICAgICAgICBzY2FsZV9jb2xvcl92aXJpZGlzX2MobGltaXRzID0gYygwLCAxKSkgKwogICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHNjaWVudGlmaWMpICsKICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2llbnRpZmljKSArCiAgICAgICAgICB0aGVtZV9idygpICsKICAgICAgICAgIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChyZXAoMC4zLDQpLCAibGluZXMiKSwKICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKICAgICAgICB9CiAgICAgICAgICApCgojIyBsb2dnZWQgb24geApkdWFsX2N1cnZlX3hsb2cucGwgPC0gcHVycnI6Om1hcDIoCiAgLnggPSBkdWFsX3Zhci5jb21iJHgsIAogIC55ID0gZHVhbF92YXIuY29tYiR5LAogICAgICB+e2dncGxvdCgpICsKICAgICAgICAgIGdlb21fcGF0aChkYXRhID0gZHVhbF9jci5mLCBhZXNfc3RyaW5nKHggPSBzcHJpbnRmKCJsb2coJXMpIiwgLnkpLCB5ID0gLngsIGNvbG9yID0gImNyIiksCiAgICAgICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KGMocmVwKDAsIG5yb3coZHVhbF9jci5mKSAtIDIpLCAwLjI1KSwgImluY2hlcyIpKSwKICAgICAgICAgICAgICAgICAgICBzaXplID0gMS41KSArCiAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBkdWFsX2NyLmYgJT4lIGZpbHRlcihyb3dfbnVtYmVyKCkgJSUgMTAgPT0xKSwgCiAgICAgICAgICAgICAgICAgICAgIGFlc19zdHJpbmcoeCA9IHNwcmludGYoImxvZyglcykiLCAueSksIHkgPSAueCwgY29sb3IgPSAiY3IiKSwgc2l6ZSA9IDMpICsKICAgICAgICAgIGxhYnMoY29sb3IgPSAiQ29udmVyc2lvbiByYXRlIiwKICAgICAgICAgICAgeCA9IHBhc3RlMCgibG9nMTAoIiwgLnksIikiKSkgKyAjIG5vdGUgdGhlIGxhYmVscyBhcmUgcmV2ZXJzZWQgYmVjYXVzZSB3ZSBzZXQgeD0geSBhbmQgeSA9IHggYWJvdmUKICAgICAgICAgIHNjYWxlX2NvbG9yX3ZpcmlkaXNfYyhsaW1pdHMgPSBjKDAsIDEpKSArCiAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NpZW50aWZpYykgKwogICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgICB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQocmVwKDAuMyw0KSwgImxpbmVzIiksCiAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCiAgICAgICAgfQogICAgICAgICAgKQoKIyMgbG9nZ2VkIG9uIHkKZHVhbF9jdXJ2ZV95bG9nLnBsIDwtIHB1cnJyOjptYXAyKAogIC54ID0gZHVhbF92YXIuY29tYiR4LCAKICAueSA9IGR1YWxfdmFyLmNvbWIkeSwKICAgICAgfntnZ3Bsb3QoKSArCiAgICAgICAgICBnZW9tX3BhdGgoZGF0YSA9IGR1YWxfY3IuZiwgYWVzX3N0cmluZyh4ID0gLnksIHkgPSBzcHJpbnRmKCJsb2coJXMpIiwgLngpLCBjb2xvciA9ICJjciIpLAogICAgICAgICAgICAgICAgICAgIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdChjKHJlcCgwLCBucm93KGR1YWxfY3IuZikgLSAyKSwgMC4yNSksICJpbmNoZXMiKSksCiAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEuNSkgKwogICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gZHVhbF9jci5mICU+JSBmaWx0ZXIocm93X251bWJlcigpICUlIDEwID09MSksIAogICAgICAgICAgICAgICAgICAgICBhZXNfc3RyaW5nKHggPSAueSwgeSA9IHNwcmludGYoImxvZyglcykiLCAueCksIGNvbG9yID0gImNyIiksIHNpemUgPSAzKSArCiAgICAgICAgICBsYWJzKGNvbG9yID0gIkNvbnZlcnNpb24gcmF0ZSIsCiAgICAgICAgICAgIHkgPSBwYXN0ZTAoImxvZzEwKCIsIC54LCIpIikpICsgIyBub3RlIHRoZSBsYWJlbHMgYXJlIHJldmVyc2VkIGJlY2F1c2Ugd2Ugc2V0IHg9IHkgYW5kIHkgPSB4IGFib3ZlCiAgICAgICAgICBzY2FsZV9jb2xvcl92aXJpZGlzX2MobGltaXRzID0gYygwLCAxKSkgKwogICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHNjaWVudGlmaWMpICsKICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgdGhlbWUocGxvdC5tYXJnaW4gPSB1bml0KHJlcCgwLjMsNCksICJsaW5lcyIpLAogICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQogICAgICAgIH0KICAgICAgICAgICkKCgojIGJvdGggbG9nZ2VkCmR1YWxfY3VydmVfbG9nLnBsIDwtIHB1cnJyOjptYXAyKAogIC54ID0gZHVhbF92YXIuY29tYiR4LCAKICAueSA9IGR1YWxfdmFyLmNvbWIkeSwKICAgICAgfntnZ3Bsb3QoKSArCiAgICAgICAgICBnZW9tX3BhdGgoZGF0YSA9IGR1YWxfY3IuZiwgYWVzX3N0cmluZyh4ID0gc3ByaW50ZigibG9nKCVzKSIsIC55KSwgeSA9IHNwcmludGYoImxvZyglcykiLCAueCksIGNvbG9yID0gImNyIiksCiAgICAgICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KGMocmVwKDAsIG5yb3coZHVhbF9jci5mKSAtIDIpLCAwLjI1KSwgImluY2hlcyIpKSwKICAgICAgICAgICAgICAgICAgICBzaXplID0gMS41KSArCiAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBkdWFsX2NyLmYgJT4lIGZpbHRlcihyb3dfbnVtYmVyKCkgJSUgMTAgPT0xKSwgCiAgICAgICAgICAgICAgICAgICAgIGFlc19zdHJpbmcoeCA9IHNwcmludGYoImxvZyglcykiLCAueSksIHkgPSBzcHJpbnRmKCJsb2coJXMpIiwgLngpLCBjb2xvciA9ICJjciIpLCBzaXplID0gMykgKwogICAgICAgICAgbGFicyhjb2xvciA9ICJDb252ZXJzaW9uIHJhdGUiLAogICAgICAgICAgICAgICB4ID0gcGFzdGUwKCJsb2cxMCgiLCAueSwiKSIpLAogICAgICAgICAgICB5ID0gcGFzdGUwKCJsb2cxMCgiLCAueCwiKSIpKSArICMgbm90ZSB0aGUgbGFiZWxzIGFyZSByZXZlcnNlZCBiZWNhdXNlIHdlIHNldCB4PSB5IGFuZCB5ID0geCBhYm92ZQogICAgICAgICAgc2NhbGVfY29sb3JfdmlyaWRpc19jKGxpbWl0cyA9IGMoMCwgMSkpICsKICAgICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgICAgdGhlbWUocGxvdC5tYXJnaW4gPSB1bml0KHJlcCgwLjMsNCksICJsaW5lcyIpLAogICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQogICAgICAgIH0KICAgICAgICAgICkKCiMgc2F2ZSBhbGwgNCBwbGF0ZXMKZ2dhcnJhbmdlKHBsb3RsaXN0ID0gZHVhbF9jdXJ2ZS5wbCwgbmNvbCA9IDIsIG5yb3cgPSAzLCBhbGlnbiA9ICJodiIpCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3Bsb3MtYmlvL2R1YWxfY3VydmUxLnRpZmYiKSwgdW5pdHMgPSAicHgiLCB3aWR0aCA9IDEwMDAsIGhlaWdodCA9IDEwMDAsIHNjYWxlID0gMS41LCBkcGk9MzAwLCAgYmcgPSAid2hpdGUiKQoKZ2dhcnJhbmdlKHBsb3RsaXN0ID0gZHVhbF9jdXJ2ZV94bG9nLnBsLCBuY29sID0gMiwgbnJvdyA9IDMsIGFsaWduID0gImh2IikKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vZHVhbF9jdXJ2ZTIudGlmZiIpLCB1bml0cyA9ICJweCIsIHdpZHRoID0gMTAwMCwgaGVpZ2h0ID0gMTAwMCwgc2NhbGUgPSAxLjUsIGRwaT0zMDAsICBiZyA9ICJ3aGl0ZSIpCgpnZ2FycmFuZ2UocGxvdGxpc3QgPSBkdWFsX2N1cnZlX3lsb2cucGwsIG5jb2wgPSAyLCBucm93ID0gMywgYWxpZ24gPSAiaHYiKQpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby9kdWFsX2N1cnZlMy50aWZmIiksIHVuaXRzID0gInB4Iiwgd2lkdGggPSAxMDAwLCBoZWlnaHQgPTEwMDAsIHNjYWxlID0gMS41LCBkcGk9MzAwLCAgYmcgPSAid2hpdGUiKQoKZ2dhcnJhbmdlKHBsb3RsaXN0ID0gZHVhbF9jdXJ2ZV9sb2cucGwsIG5jb2wgPSAyLCBucm93ID0gMywgYWxpZ24gPSAiaHYiKQpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby9kdWFsX2N1cnZlNC50aWZmIiksIHVuaXRzID0gInB4Iiwgd2lkdGggPSAxMDAwLCBoZWlnaHQgPSAxMDAwLCBzY2FsZSA9IDEuNSwgZHBpPTMwMCwgIGJnID0gIndoaXRlIikKYGBgCgoKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwojIHJlYWwgbGlmZSBkaXNlYXNlIGN1cnZlCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIyBleGVjdXRlIGNvZGUgZnJvbSByZXBvcnQgMTAgdG8gZ2V0IGZpbmFsIGRhdGFzZXQKVGhlIGZvbGxvd2luZyBncmFwaHMgd2lsbCBiZSBtYWRlOgotIFIgdnMgaVJCQwotIFIgbG9nMTAgdnMgaVJCQwotIFIgdnMgaVJCQyBsb2cxMAotIFIgbG9nMTAgdnMgaVJCQyBsb2cxMAoKLSBHIHZzIGlSQkMKLSBHIGxvZzEwIHZzIGlSQkMKLSBHIHZzIGlSQkMgbG9nMTAKLSBHIGxvZzEwIHZzIGlSQkMgbG9nMTAKCi0gUiB2cyBHCi0gUiBsb2cxMCB2cyBHCi0gUiB2cyBHIGxvZzEwCi0gUiBsb2cxMCB2cyBHIGxvZzEwCgpSIG9uIHktYXhpcwpgYGB7cn0Kcl9pLmRjIDwtIGdncGxvdChleHBfc3MuZGYpICsKICBnZW9tX3BvaW50KGFlcyh5ID0gUkJDLCB4ID0gYXNleCkpICsKICBnZW9tX3BhdGgoYWVzKHkgPSBSQkMsIHggPSBhc2V4LCBjb2xvdXIgPSBkYXksIGdyb3VwID0gaWQpLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKGxpbWl0cyA9IGMoMywgMjEpKSArCiAgbGFicyh4ID0gImlSQkMgcGVyIMK1TCIsIHkgPSAiUkJDIHBlciDCtUwiLCBjb2xvciA9ICJEYXlzXG5wb3N0LWluZmVjdGlvbiIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUUlVFKSkKCnJsb2dfaS5kYyA8LSBnZ3Bsb3QoZXhwX3NzLmRmKSArCiAgZ2VvbV9wb2ludChhZXMoeSA9IGxvZzEwKFJCQyksIHggPSBhc2V4KSkgKwogIGdlb21fcGF0aChhZXMoeSA9IGxvZzEwKFJCQyksIHggPSBhc2V4LCBjb2xvdXIgPSBkYXksIGdyb3VwID0gaWQpLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKGxpbWl0cyA9IGMoMywgMjEpKSArCiAgbGFicyh4ID0gImlSQkMgcGVyIMK1TCIsIHkgPSAibG9nMTAoUkJDKSBwZXIgwrVMIiwgY29sb3IgPSAiRGF5c1xucG9zdC1pbmZlY3Rpb24iKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSkpCgpyX2lsb2cuZGMgPC1nZ3Bsb3QoZXhwX3NzLmRmKSArCiAgZ2VvbV9wb2ludChhZXMoeSA9IFJCQywgeCA9IGxvZzEwKGFzZXgpKSkgKwogIGdlb21fcGF0aChhZXMoeSA9IFJCQywgeCA9IGxvZzEwKGFzZXgpLCBjb2xvdXIgPSBkYXksIGdyb3VwID0gaWQpLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKGxpbWl0cyA9IGMoMywgMjEpKSArCiAgbGFicyh4ID0gImxvZzEwKGlSQkMpIHBlciDCtUwiLCB5ID0gIlJCQyBwZXIgwrVMIiwgY29sb3IgPSAiRGF5c1xucG9zdC1pbmZlY3Rpb24iKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSkpCgpybG9nX2lsb2cuZGMgPC0gZ2dwbG90KGV4cF9zcy5kZikgKwogIGdlb21fcG9pbnQoYWVzKHkgPSBsb2cxMChSQkMpLCB4ID0gbG9nMTAoYXNleCkpKSArCiAgZ2VvbV9wYXRoKGFlcyh5ID0gbG9nMTAoUkJDKSwgeCA9IGxvZzEwKGFzZXgpLCBjb2xvdXIgPSBkYXksIGdyb3VwID0gaWQpLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKGxpbWl0cyA9IGMoMywgMjEpKSArCiAgbGFicyh4ID0gImxvZzEwKGlSQkMpIHBlciDCtUwiLCB5ID0gImxvZzEwKFJCQykgcGVyIMK1TCIsIGNvbG9yID0gIkRheXNcbnBvc3QtaW5mZWN0aW9uIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFRSVUUpKQpgYGAKCkcgb24geS1heGlzCmBgYHtyfQpnX2kuZGMgPC0gZ2dwbG90KGV4cF9zcy5kZikgKwogIGdlb21fcG9pbnQoYWVzKHkgPSBnYW0sIHggPSBhc2V4KSkgKwogIGdlb21fcGF0aChhZXMoeSA9IGdhbSwgeCA9IGFzZXgsIGNvbG91ciA9IGRheSwgZ3JvdXAgPSBpZCksIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIHRoZW1lX2J3KCkgKyAKICBzY2FsZV9jb2xvcl92aXJpZGlzX2MobGltaXRzID0gYygzLCAyMSkpICsKICBsYWJzKHggPSAiaVJCQyBwZXIgwrVMIiwgeSA9ICJHYW1ldG9jeXRlIHBlciDCtUwiLCBjb2xvciA9ICJEYXlzXG5wb3N0LWluZmVjdGlvbiIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUUlVFKSkKCmdsb2dfaS5kYyA8LSBnZ3Bsb3QoZXhwX3NzLmRmKSArCiAgZ2VvbV9wb2ludChhZXMoeSA9IGxvZzEwKGdhbSksIHggPSBhc2V4KSkgKwogIGdlb21fcGF0aChhZXMoeSA9IGxvZzEwKGdhbSksIHggPSBhc2V4LCBjb2xvdXIgPSBkYXksIGdyb3VwID0gaWQpLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKGxpbWl0cyA9IGMoMywgMjEpKSArCiAgbGFicyh4ID0gImlSQkMgcGVyIMK1TCIsIHkgPSAibG9nMTAoR2FtZXRvY3l0ZSkgcGVyIMK1TCIsIGNvbG9yID0gIkRheXNcbnBvc3QtaW5mZWN0aW9uIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFRSVUUpKQoKZ19pbG9nLmRjIDwtIGdncGxvdChleHBfc3MuZGYpICsKICBnZW9tX3BvaW50KGFlcyh5ID0gZ2FtLCB4ID0gbG9nMTAoYXNleCkpKSArCiAgZ2VvbV9wYXRoKGFlcyh5ID0gZ2FtLCB4ID0gbG9nMTAoYXNleCksIGNvbG91ciA9IGRheSwgZ3JvdXAgPSBpZCksIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIHRoZW1lX2J3KCkgKyAKICBzY2FsZV9jb2xvcl92aXJpZGlzX2MobGltaXRzID0gYygzLCAyMSkpICsKICBsYWJzKHggPSAibG9nMTAoaVJCQykgcGVyIMK1TCIsIHkgPSAiR2FtZXRvY3l0ZSBwZXIgwrVMIiwgY29sb3IgPSAiRGF5c1xucG9zdC1pbmZlY3Rpb24iKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSkpCgpnbG9nX2lsb2cuZGMgPC0gZ2dwbG90KGV4cF9zcy5kZikgKwogIGdlb21fcG9pbnQoYWVzKHkgPSBsb2cxMChnYW0pLCB4ID0gbG9nMTAoYXNleCkpKSArCiAgZ2VvbV9wYXRoKGFlcyh5ID0gbG9nMTAoZ2FtKSwgeCA9IGxvZzEwKGFzZXgpLCBjb2xvdXIgPSBkYXksIGdyb3VwID0gaWQpLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKGxpbWl0cyA9IGMoMywgMjEpKSArCiAgbGFicyh4ID0gImxvZzEwKGlSQkMpIHBlciDCtUwiLCB5ID0gImxvZzEwKEdhbWV0b2N5dGUpIHBlciDCtUwiLCBjb2xvciA9ICJEYXlzXG5wb3N0LWluZmVjdGlvbiIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUUlVFKSkKYGBgCgpSIHZzIEcKYGBge3J9CnJfZy5kYyA8LSBnZ3Bsb3QoZXhwX3NzLmRmKSArCiAgZ2VvbV9wb2ludChhZXMoeSA9IFJCQywgeCA9IGdhbSkpICsKICBnZW9tX3BhdGgoYWVzKHkgPSBSQkMsIHggPSBnYW0sIGNvbG91ciA9IGRheSwgZ3JvdXAgPSBpZCksIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIHRoZW1lX2J3KCkgKyAKICBzY2FsZV9jb2xvcl92aXJpZGlzX2MobGltaXRzID0gYygzLCAyMSkpICsKICBsYWJzKHggPSAiR2FtZXRvY3l0ZSBwZXIgwrVMIiwgeSA9ICJSQkMgcGVyIMK1TCIsIGNvbG9yID0gIkRheXNcbnBvc3QtaW5mZWN0aW9uIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFRSVUUpKQoKcmxvZ19nLmRjIDwtIGdncGxvdChleHBfc3MuZGYpICsKICBnZW9tX3BvaW50KGFlcyh5ID0gbG9nMTAoUkJDKSwgeCA9IGdhbSkpICsKICBnZW9tX3BhdGgoYWVzKHkgPSBsb2cxMChSQkMpLCB4ID0gZ2FtLCBjb2xvdXIgPSBkYXksIGdyb3VwID0gaWQpLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKGxpbWl0cyA9IGMoMywgMjEpKSArCiAgbGFicyh4ID0gIkdhbWV0b2N5dGUgcGVyIMK1TCIsIHkgPSAibG9nMTAoUkJDIHBlciDCtUwpIiwgY29sb3IgPSAiRGF5c1xucG9zdC1pbmZlY3Rpb24iKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSkpCgpyX2dsb2cuZGMgPC0gZ2dwbG90KGV4cF9zcy5kZikgKwogIGdlb21fcG9pbnQoYWVzKHkgPSBSQkMsIHggPSBsb2cxMChnYW0pKSkgKwogIGdlb21fcGF0aChhZXMoeSA9IFJCQywgeCA9IGxvZzEwKGdhbSksIGNvbG91ciA9IGRheSwgZ3JvdXAgPSBpZCksIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIHRoZW1lX2J3KCkgKyAKICBzY2FsZV9jb2xvcl92aXJpZGlzX2MobGltaXRzID0gYygzLCAyMSkpICsKICBsYWJzKHggPSAibG9nMTAoR2FtZXRvY3l0ZSkgcGVyIMK1TCIsIHkgPSAiUkJDIHBlciDCtUwiLCBjb2xvciA9ICJEYXlzXG5wb3N0LWluZmVjdGlvbiIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUUlVFKSkKCnJsb2dfZ2xvZy5kYyA8LSBnZ3Bsb3QoZXhwX3NzLmRmKSArCiAgZ2VvbV9wb2ludChhZXMoeSA9IGxvZzEwKFJCQyksIHggPSBsb2cxMChnYW0pKSkgKwogIGdlb21fcGF0aChhZXMoeSA9IGxvZzEwKFJCQyksIHggPSBsb2cxMChnYW0pLCBjb2xvdXIgPSBkYXksIGdyb3VwID0gaWQpLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpc19jKGxpbWl0cyA9IGMoMywgMjEpKSArCiAgbGFicyh4ID0gImxvZzEwKEdhbWV0b2N5dGUpIHBlciDCtUwiLCB5ID0gImxvZzEwKFJCQykgcGVyIMK1TCIsIGNvbG9yID0gIkRheXNcbnBvc3QtaW5mZWN0aW9uIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFRSVUUpKQpgYGAKCiMgcGxvdCB0b2dldGhlcgpgYGB7cn0KZ2dhcnJhbmdlKHJfaS5kYywgcmxvZ19pLmRjLCByX2lsb2cuZGMsIHJsb2dfaWxvZy5kYywKICAgICAgICAgIGdfaS5kYywgZ2xvZ19pLmRjLCBnX2lsb2cuZGMsIGdsb2dfaWxvZy5kYywKICAgICAgICAgIHJfZy5kYywgcmxvZ19nLmRjLCByX2dsb2cuZGMsIHJsb2dfZ2xvZy5kYywgCiAgICAgICAgICBuY29sID0gNCwgbnJvdyA9IDMsIGFsaWduID0gImh2IiwgY29tbW9uLmxlZ2VuZCA9IFQpCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3Bsb3MtYmlvL2V4cF9kaXNlYXNlLWN1cnZlLnRpZmYiKSwgdW5pdHMgPSAicHgiLCB3aWR0aCA9IDIyNTAsIGhlaWdodCA9IDE1MDAsIHNjYWxlID0gMiwgZHBpPTMwMCwgIGJnID0gIndoaXRlIikKYGBgCgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIyBzdGF0aWMgY29tcGV0aXRpb24KIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMtLS0tLS0tIGhlYXQgbWFwIC0tLS0tLS0tLS0tLS0tLSMKIyBjYWxjdWxhdGUgZml0bmVzcyBkaWZmZXJlbmNlIGZvciAyMCBkYXlzCmBgYHtyfQojIGdldCBkeW5hbWljcwpzdGF0aWMubHMgPC0gbGlzdC5maWxlcyhwYXRoID0gaGVyZSgiZGF0YS9jaV9zdGF0aWMvIiksIHBhdHRlcm4gPSAiKi5wYXJxdWV0IiwgZnVsbC5uYW1lcyA9IFQpCnN0YXRpYy5scyA8LSBsYXBwbHkoc3RhdGljLmxzLCByZWFkX3BhcnF1ZXQpCgojIGdldCBmaXRuZXNzIGF0IGRheSAyMCAob3B0aW1pemVkIGZvciAyMCBkYXlzKQpzdGF0aWNfZml0bmVzcy5scyA8LSBtY2xhcHBseShzdGF0aWMubHMsIGZ1bmN0aW9uKHgpewogIHggJT4lIGZpbHRlcih0aW1lID09IDIwICYgdmFyaWFibGUgJWluJSBjKCJ0YXVfY3VtMSIsICJ0YXVfY3VtMiIpKQp9KQpzdGF0aWNfZml0bmVzcy5kZiA8LSBkby5jYWxsKHJiaW5kLCBzdGF0aWNfZml0bmVzcy5scykKCnN0YXRpY19maXRuZXNzLmRmIDwtIHRpZHlyOjpwaXZvdF93aWRlcihzdGF0aWNfZml0bmVzcy5kZiwgbmFtZXNfZnJvbSA9ICJ2YXJpYWJsZSIsIGlkX2NvbHMgPSBjKCJpZF8xIiwgImlkXzIiKSkgJT4lIAogIGdyb3VwX2J5KGlkXzEsIGlkXzIpICU+JSAKICBtdXRhdGUoZml0bmVzc19kaWZmZXJlbmNlID0gdGF1X2N1bTEtdGF1X2N1bTIpCndyaXRlLmNzdihzdGF0aWNfZml0bmVzcy5kZiwgaGVyZSgiZGF0YS9jaV9zdGF0aWMuY3N2IikpCmBgYAoKIyBpbXBvcnQgYW5kIHByb2Nlc3MgZGF0YQpgYGB7cn0KIyBpbXBvcnQgaW4gZGF0YXNldApzdGF0aWMuZGYgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9jaV9zdGF0aWMuY3N2IikpCmV6X2xhYmVsIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvZXpfbGFiZWwuY3N2IikpCgojIGpvaW4gd2l0aCBsYWJlbGxpbmcKc3RhdGljLmRmMiA8LSBzdGF0aWMuZGYgJT4lIAogIGxlZnRfam9pbihzZWxlY3QoZXpfbGFiZWwsIGlkX2NpLCBsYWJlbF9jaV8xID0gbGFiZWxfY2kpLCBieSA9IGMoImlkXzEiID0gImlkX2NpIikpICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGV6X2xhYmVsLCBpZF9jaSwgbGFiZWxfY2lfMiA9IGxhYmVsX2NpKSwgYnkgPSBjKCJpZF8yIiA9ICJpZF9jaSIpKSAlPiUgCiAgc2VsZWN0KGxhYmVsX2NpXzEsIGxhYmVsX2NpXzIsIGZpdG5lc3NfZGlmZmVyZW5jZSkgJT4lIAogIG11dGF0ZShsYWJlbF9jaV8xID0gZ3N1YigibG9nIiwgImxvZzEwIiwgbGFiZWxfY2lfMSksCiAgICAgICAgIGxhYmVsX2NpXzIgPSBnc3ViKCJsb2ciLCAibG9nMTAiLCBsYWJlbF9jaV8yKSkKCiMgZ2V0IHJldmVyc2Ugb3JkZXIsIHdoaWNoIGlzIHNpbXBseSBpbnZvdmxlcyBzd2l0Y2hpbmcgdGhlIGN1ZXMgYXJvdW5kIHRoZSBtdWx0aXBseWluZyB0aGUgZml0bmVzcyBieSBuZWdhdGl2ZSAxCnN0YXRpYy5kZjMgPC0gc3RhdGljLmRmMgpuYW1lcyhzdGF0aWMuZGYzKSA8LSBjKCJsYWJlbF9jaV8yIiwgImxhYmVsX2NpXzEiLCAiZml0bmVzc19kaWZmZXJlbmNlIikKc3RhdGljLmRmMyRmaXRuZXNzX2RpZmZlcmVuY2UgPC0gc3RhdGljLmRmMiRmaXRuZXNzX2RpZmZlcmVuY2UgKiAtMQoKIyBqb2luCnN0YXRpYy5kZjQgPC0gcmJpbmQoc3RhdGljLmRmMiwgc3RhdGljLmRmMykKCiMgZ2V0IG1lYW4Kc3RhdGljLm1lYW4gPC0gc3RhdGljLmRmNCAlPiUgCiAgZGlzdGluY3QobGFiZWxfY2lfMSwgbGFiZWxfY2lfMiwgLmtlZXBfYWxsID0gVCkgJT4lIAogIGdyb3VwX2J5KGxhYmVsX2NpXzEpICU+JSAKICBzdW1tYXJpemUobWVhbl9maXRuZXNzID0gbWVhbihmaXRuZXNzX2RpZmZlcmVuY2UsIG5hLnJtID0gVCkpCiAgCgojIGpvaW4gc3RhdGljLmRmNCB3aXRoIG1lYW4gZm9yIG9yZGVyIHNvcnRpbmcKc3RhdGljLmRmNSA8LSBzdGF0aWMuZGY0ICU+JSAKICBsZWZ0X2pvaW4oc3RhdGljLm1lYW4sIGJ5ID0gImxhYmVsX2NpXzEiKSAlPiUgCiAgbXV0YXRlKGxhYmVsX2NpXzEgPSBmY3RfcmVvcmRlcihsYWJlbF9jaV8xLCBtZWFuX2ZpdG5lc3MpLAogICAgICAgICBsYWJlbF9jaV8yID0gZmN0X3JlbGV2ZWwobGFiZWxfY2lfMiwgbGV2ZWxzKHN0YXRpYy5kZjUkbGFiZWxfY2lfMSkpKQpgYGAKCiMgcGxvdApgYGB7cn0KIyBoZWF0bWFwCnN0YXRpYy5wbDEgPC0gZ2dwbG90KGRhdGEgPSBzdGF0aWMuZGY1LCBhZXMoeCA9IGxhYmVsX2NpXzIsIHkgPSBsYWJlbF9jaV8xLCBtZWFuX2ZpdG5lc3MsIGZpbGwgPSBmaXRuZXNzX2RpZmZlcmVuY2UpKSsKICBnZW9tX3RpbGUoY29sb3IgPSAiYmxhY2siKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudDIobG93ID0gIiNmYzhkNTkiLCBoaWdoID0gIiM0NTc1YjQiLCBtaWQgPSAid2hpdGUiLCAKICAgbWlkcG9pbnQgPSAwLCBzcGFjZSA9ICJMYWIiLCBsaW0gPSBjKC0wLjk1LCAwLjk1KSwgbmFtZT0iRml0bmVzc1xuZGlmZmVyZW5jZSIpICsKICB0aGVtZV9taW5pbWFsKCkgKyAgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImxlZnQiLAogIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIHZqdXN0ID0gMSwgaGp1c3QgPSAxKSwKICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSwKICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwKICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLAogIHBsb3QubWFyZ2luPW1hcmdpbihyID0gLTEsIGwgPSAtMSwgdW5pdCA9ICJwdCIpKSArIAogIGxhYnMoeCA9ICJTdHJhaW4gMiBjdWUiLCB5ID0gIlN0cmFpbiAxIGN1ZSIpICsKICBjb29yZF9maXhlZCgpCgojIG1lYW4gCnN0YXRpYy5wbDIgPC0gZ2dwbG90KCkgKwogIGdlb21fYmFyKGRhdGEgPSAgc3RhdGljLm1lYW4sIGFlcyh5ID0gZmN0X3Jlb3JkZXIobGFiZWxfY2lfMSwgbWVhbl9maXRuZXNzKSwgeCA9IG1lYW5fZml0bmVzcyksIHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgbGFicyh5ID0gIiIsIHggPSAiTWVhbiBmaXRuZXNzXG5kaWZmZXJlbmNlIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBsb3QubWFyZ2luID0gbWFyZ2luKGwgPSAwKSwKICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksCiAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpY2tzLnk9ZWxlbWVudF9ibGFuaygpKQoKZ2dhcnJhbmdlKHN0YXRpYy5wbDEsIHN0YXRpYy5wbDIsIGFsaWduID0gImh2Iiwgd2lkdGhzID0gYygxLCAwLjIpKQpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby9zdGF0aWNfY29tcGV0aXRpb25fYS50aWZmIiksIHVuaXRzID0gInB4Iiwgd2lkdGggPSAyMjUwLCBoZWlnaHQgPSAxNTAwLCBzY2FsZSA9IDEuMiwgZHBpPTMwMCwgIGJnID0gIndoaXRlIikKYGBgCgojLS0tLS0tIGVmZmVjdCBjdWUgcGVyY2VwdGlvbiAtLS0tLS0tIwojIyBsb2dnaW5nCmBgYHtyfQojIGdldCBub24tbG9nZ2VkIHBhaXJpbmdzCnN0YXRpY19ub2xvZyA8LSBzdGF0aWMuZGYyICU+JSAKICBtdXRhdGUoY3VlXzEgPSB0cmltd3MoZ3N1YigiXFwgLioiLCAiIiwgbGFiZWxfY2lfMSkpLAogICAgICAgICBsb2dfMSA9IGNhc2Vfd2hlbigKICAgICAgICAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJsb2ciKSB+ICJsb2ciLAogICAgICAgICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgImxvZyIsIG5lZ2F0ZSA9IFQpIH4gIm5vbmUiKSkgJT4lIAogIGZpbHRlcihsb2dfMSA9PSAibm9uZSIpCgpzdGF0aWNfbG9nIDwtIHN0YXRpYy5kZjIgJT4lIAogIG11dGF0ZShjdWVfMSA9IHRyaW13cyhnc3ViKCJcXCAuKiIsICIiLCBsYWJlbF9jaV8xKSksCiAgICAgICAgIGxvZ18xID0gY2FzZV93aGVuKAogICAgICAgICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgImxvZyIpIH4gImxvZyIsCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIiwgbmVnYXRlID0gVCkgfiAibm9uZSIpKSAlPiUgCiAgZmlsdGVyKGxvZ18xID09ICJsb2ciKQoKc3RhdGljX2xvZy5kZiA8LSBsZWZ0X2pvaW4oCiAgc2VsZWN0KHN0YXRpY19ub2xvZywgY3VlXzEsIGxhYmVsX2NpXzIsIGxvZ18xLCBOb25lID0gZml0bmVzc19kaWZmZXJlbmNlKSwKICBzZWxlY3Qoc3RhdGljX2xvZywgY3VlXzEsIGxhYmVsX2NpXzIsIGxvZ18xLCBMb2cgPSBmaXRuZXNzX2RpZmZlcmVuY2UpLAogIGJ5ID0gYygiY3VlXzEiLCAibGFiZWxfY2lfMiIpKSAlPiUgCiAgZmlsdGVyKCFpcy5uYShOb25lKSAmICFpcy5uYShMb2cpKSAlPiUgCiAgbXV0YXRlKGNsYXNzaWZpY2F0aW9uID0gaWZlbHNlKExvZyA+IE5vbmUsICJMb2dnZWQgYmV0dGVyIiwgIk5vdCBsb2dnZWQgYmV0dGVyIikpCmBgYAoKIyBjb21iaW5lZApgYGB7cn0Kc3RhdGljX25vY29tYiA8LSBzdGF0aWMuZGYyICU+JSAKICBtdXRhdGUoY3VlXzEgPSBpZmVsc2UoCiAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJzdW0iKSwgIkkrSWciLAogICAgdHJpbXdzKGdzdWIoIisxLip8XFwgbG9nIiwgIiIsIGxhYmVsX2NpXzEpKQogICksCiAgbG9nXzEgPSBjYXNlX3doZW4oCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIikgfiAibG9nIiwKICAgICAgICAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJsb2ciLCBuZWdhdGUgPSBUKSB+ICJub25lIiksCiAgICBjb21iXzEgPSBjYXNlX3doZW4oCiAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICIxK3xzdW0iKSB+ICJjb21iIiwKICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgIjErfHN1bSIsIG5lZ2F0ZSA9IFQpIH4gIm5vbmUiIAogICkpICU+JSAKICBmaWx0ZXIoY29tYl8xID09ICJub25lIikKCnN0YXRpY19jb21iIDwtIHN0YXRpYy5kZjIgJT4lIAogIG11dGF0ZShjdWVfMSA9IGlmZWxzZSgKICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgInN1bSIpLCAiSStJZyIsCiAgICB0cmltd3MoZ3N1YigiKzEuKnxcXCBsb2ciLCAiIiwgbGFiZWxfY2lfMSkpCiAgKSwKICBsb2dfMSA9IGNhc2Vfd2hlbigKICAgICAgICAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJsb2ciKSB+ICJsb2ciLAogICAgICAgICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgImxvZyIsIG5lZ2F0ZSA9IFQpIH4gIm5vbmUiKSwKICAgIGNvbWJfMSA9IGNhc2Vfd2hlbigKICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgIjErfHN1bSIpIH4gImNvbWIiLAogICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAiMSt8c3VtIiwgbmVnYXRlID0gVCkgfiAibm9uZSIgCiAgKSkgJT4lIAogIGZpbHRlcihjb21iXzEgPT0gImNvbWIiKQogIApzdGF0aWNfY29tYi5kZiA8LSBsZWZ0X2pvaW4oCiAgc2VsZWN0KHN0YXRpY19ub2NvbWIsIGN1ZV8xLCBsYWJlbF9jaV8yLCBsb2dfMSwgU2VsZiA9IGZpdG5lc3NfZGlmZmVyZW5jZSksCiAgc2VsZWN0KHN0YXRpY19jb21iLCBjdWVfMSwgbGFiZWxfY2lfMiwgbG9nXzEsIFRvdGFsID0gZml0bmVzc19kaWZmZXJlbmNlKSwKICBieSA9IGMoImN1ZV8xIiwgImxvZ18xIiwgImxhYmVsX2NpXzIiKSkgJT4lIAogIGZpbHRlcighaXMubmEoVG90YWwpICYgIWlzLm5hKFNlbGYpKSAlPiUgCiAgbXV0YXRlKGNsYXNzaWZpY2F0aW9uID0gaWZlbHNlKFRvdGFsID4gU2VsZiwgIlRvdGFsIGJldHRlciIsICJTZWxmIGJldHRlciIpKQpgYGAKCiMgcGxvdApgYGB7cn0Kc3RhdGljX2xvZy5wbCA8LSBnZ3BhaXJlZChzdGF0aWNfbG9nLmRmLCBjb25kMSA9ICJOb25lIiwgY29uZDIgPSAiTG9nIiwgbGluZS5jb2xvciA9ICJjbGFzc2lmaWNhdGlvbiIsIGFscGhhID0gMC41KSArCiAgbGFicyh4ID0gIkN1ZSBwZXJjZXB0aW9uIiwgeSA9ICJGaXRuZXNzIGRpZmZlcmVuY2UiLCBjb2xvciA9ICJFZmZlY3QiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIk5vdCBsb2dnZWQgYmV0dGVyIiA9ICIjZmM4ZDU5IiwgIkxvZ2dlZCBiZXR0ZXIiID0gIiM0NTc1YjQiKSkgKwogIHN0YXRfY29tcGFyZV9tZWFucyhwYWlyZWQgPSBUUlVFLCBoanVzdCA9IC0wLjEpCgpzdGF0aWNfY29tYi5wbCA8LSBnZ3BhaXJlZChzdGF0aWNfY29tYi5kZiwgY29uZDEgPSAiVG90YWwiLCBjb25kMiA9ICJTZWxmIiwgbGluZS5jb2xvciA9ICJjbGFzc2lmaWNhdGlvbiIsIGFscGhhID0gMC41KSArCiAgbGFicyh4ID0gIkN1ZSBwZXJjZXB0aW9uIiwgeSA9ICJGaXRuZXNzIGRpZmZlcmVuY2UiLCBjb2xvciA9ICJFZmZlY3QiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIlRvdGFsIGJldHRlciIgPSAiI2ZjOGQ1OSIsICJTZWxmIGJldHRlciIgPSAiIzQ1NzViNCIpKSArCiAgc3RhdF9jb21wYXJlX21lYW5zKHBhaXJlZCA9IFRSVUUsIGhqdXN0ID0gLTAuMikKCmdnYXJyYW5nZShzdGF0aWNfbG9nLnBsLCBzdGF0aWNfY29tYi5wbCwgbmNvbCA9IDEsIG5yb3cgPSAyLCBhbGlnbiA9ICJ2IikKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vc3RhdGljX2NvbXBldGl0aW9uX2IudGlmZiIpLCB1bml0cyA9ICJweCIsIHdpZHRoID0gMTAwMCwgaGVpZ2h0ID0gMjAwMCwgc2NhbGUgPSAxLjIsIGRwaT0zMDAsICBiZyA9ICJ3aGl0ZSIpCmBgYAoKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCnN0YXRpYyBjb21wZXRpdGlvbiBkeW5hbWljcwojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIy0tLS0tLS0tLS0tRyBsb2cxMC0tLS0tLS0tLS0tLSMKYGBge3J9CiMgaW1wb3J0IGluIGR5bmFtaWNzIHRoYXQgY29udGFpbnMgR19sb2cKR2xvZ19zdGF0aWMubHMgPC0gbGlzdC5maWxlcyhoZXJlKCJkYXRhL2NpX3N0YXRpYyIpLCBwYXR0ZXJuID0gIi4qX0ctaV9sb2cuKlxcLnBhcnF1ZXQiLCBmdWxsLm5hbWVzID0gVCkKR2xvZ19zdGF0aWMuZHluIDwtIGxhcHBseShHbG9nX3N0YXRpYy5scywgcmVhZF9wYXJxdWV0KQpHbG9nX3N0YXRpYy5keW4gPC0gZG8uY2FsbChyYmluZCwgR2xvZ19zdGF0aWMuZHluKSAKR2xvZ19zdGF0aWMuZHluMiA8LSBHbG9nX3N0YXRpYy5keW4gJT4lIAogIGxlZnRfam9pbihzZWxlY3QoZXpfbGFiZWwsIGlkX2NpLCBsYWJlbF9jaSksIGJ5ID0gYygiaWRfMSIgPSAiaWRfY2kiKSkKCiMgaWRfMSByZXByZXNlbnRzIGNvbXBldGl0b3IsIGlkXzIgcmVwcmVzZW50cyBHLWkgbG9nCnVuaXF1ZShHbG9nX3N0YXRpYy5keW4kaWRfMSkKdW5pcXVlKEdsb2dfc3RhdGljLmR5biRpZF8yKQoKIyBwbG90dGluZyBjb252ZXJzaW9uIHJhdGUgZHluYW1pYyAKR2xvZ19jci5wbCA8LSBHbG9nX3N0YXRpYy5keW4yICU+JSAKICBmaWx0ZXIodmFyaWFibGUgPT0gImNyXzIiKSAlPiUgCmdncGxvdChhZXMoeCA9IHRpbWUsIHkgPSBsYWJlbF9jaSwgZmlsbCA9IHZhbHVlKSkgKwogIGdlb21fcmFzdGVyKCkgKwogIHhsaW0oMSwgMTQpICsKICBsYWJzKHggPSAiIiwgeSA9ICJDb21wZXRpbmcgY3VlcyIsIGZpbGwgPSAiQ29udmVyc2lvbiByYXRlIikgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMudGl0bGUueD1lbGVtZW50X2JsYW5rKCkpCgojIHBsb3R0aW5nIEcKR2xvZ19HLnBsIDwtIEdsb2dfc3RhdGljLmR5bjIgJT4lIAogIGZpbHRlcih2YXJpYWJsZSA9PSAiRzIiKSAlPiUgCiAgbXV0YXRlKHZhbHVlID0gbG9nMTAodmFsdWUpKSAlPiUgCmdncGxvdChhZXMoeCA9IHRpbWUsIHkgPSBsYWJlbF9jaSwgZmlsbCA9IHZhbHVlKSkgKwogIGdlb21fcmFzdGVyKCkgKwogIHhsaW0oMSwgMTQpICsKICBsYWJzKHggPSAiVGltZSAoZGF5cykiLCB5ID0gIkNvbXBldGluZyBjdWVzIiwgZmlsbCA9ICJHYW1ldG9jeXRlIChsb2cxMCkiKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2Mob3B0aW9uID0gIkMiKSArCiAgdGhlbWVfYncoKSsKICB0aGVtZShheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpKQoKIyBwbG90dGluZyBJIApHbG9nX0kucGwgPC0gR2xvZ19zdGF0aWMuZHluMiAlPiUgCiAgZmlsdGVyKHZhcmlhYmxlID09ICJJMiIpICU+JSAKZ2dwbG90KGFlcyh4ID0gdGltZSwgeSA9IGxhYmVsX2NpLCBmaWxsID0gdmFsdWUpKSArCiAgZ2VvbV9yYXN0ZXIoKSArCiAgeGxpbSgxLCAxNCkgKwogIGxhYnMoeCA9ICJUaW1lIChkYXlzKSIsIHkgPSAiQ29tcGV0aW5nIGN1ZXMiLCBmaWxsID0gIkFzZXh1YWwgaVJCQyIpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb24gPSAiQSIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpKQoKIyBwbG90dGluZyB0YXUKR2xvZ190YXUucGwgPC0gR2xvZ19zdGF0aWMuZHluMiAlPiUgCiAgZmlsdGVyKHZhcmlhYmxlID09ICJ0YXUyIikgJT4lIApnZ3Bsb3QoYWVzKHggPSB0aW1lLCB5ID0gbGFiZWxfY2ksIGZpbGwgPSB2YWx1ZSkpICsKICBnZW9tX3Jhc3RlcigpICsKICB4bGltKDEsIDE0KSArCiAgbGFicyh4ID0gIlRpbWUgKGRheXMpIiwgeSA9ICJDb21wZXRpbmcgY3VlcyIsIGZpbGwgPSAiVHJhbnNtaXNzaW9uXG5wb3RlbnRpYWwiKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2Mob3B0aW9uID0gIkIiKSArCiAgdGhlbWVfYncoKSAKCiMgcGxvdCB0b2dldGhlcgpHbG9nX2R5bi5wbCA8LSBnZ2FycmFuZ2UoR2xvZ19jci5wbCwgR2xvZ19JLnBsLCBHbG9nX0cucGwsIEdsb2dfdGF1LnBsLCBuY29sID0gMSwgYWxpZ24gPSAidiIpCgpgYGAKCiMtLS0tLS0tLS0tLVIgYXMgY3VlLS0tLS0tLS0tLS0jCmBgYHtyfQojIGltcG9ydCBpbiBkeW5hbWljcyB0aGF0IGNvbnRhaW5zIFJfbm9uZQpSX3N0YXRpYy5scyA8LSBsaXN0LmZpbGVzKGhlcmUoImRhdGEvY2lfc3RhdGljIiksIHBhdHRlcm4gPSAiXlJfbm9uZS4qLnBhcnF1ZXQiLCBmdWxsLm5hbWVzID0gVCkKUl9zdGF0aWMuZHluIDwtIGxhcHBseShSX3N0YXRpYy5scywgcmVhZF9wYXJxdWV0KQpSX3N0YXRpYy5keW4gPC0gZG8uY2FsbChyYmluZCwgUl9zdGF0aWMuZHluKQpSX3N0YXRpYy5keW4yIDwtIFJfc3RhdGljLmR5biAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChlel9sYWJlbCwgaWRfY2ksIGxhYmVsX2NpKSwgYnkgPSBjKCJpZF8yIiA9ICJpZF9jaSIpKQoKIyBpZF8xIGlzIFIsIGlkXzIgaXMgY29tcGV0aXRvcgp1bmlxdWUoUl9zdGF0aWMuZHluJGlkXzIpCgojIHBsb3R0aW5nIGNvbnZlcnNpb24gcmF0ZSBkeW5hbWljIApSX2NyLnBsIDwtIFJfc3RhdGljLmR5bjIgJT4lIAogIGZpbHRlcih2YXJpYWJsZSA9PSAiY3JfMSIpICU+JSAKZ2dwbG90KGFlcyh4ID0gdGltZSwgeSA9IGxhYmVsX2NpLCBmaWxsID0gdmFsdWUpKSArCiAgZ2VvbV9yYXN0ZXIoKSArCiAgeGxpbSgxLCAxNCkgKwogIGxhYnMoeCA9ICIiLCB5ID0gIkNvbXBldGluZyBjdWVzIiwgZmlsbCA9ICJDb252ZXJzaW9uIHJhdGUiKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2MoKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50aXRsZS54PWVsZW1lbnRfYmxhbmsoKSkKCiMgcGxvdHRpbmcgUgpSX1IucGwgPC0gUl9zdGF0aWMuZHluMiAlPiUgCiAgZmlsdGVyKHZhcmlhYmxlID09ICJSIikgJT4lIApnZ3Bsb3QoYWVzKHggPSB0aW1lLCB5ID0gbGFiZWxfY2ksIGZpbGwgPSB2YWx1ZSkpICsKICBnZW9tX3Jhc3RlcigpICsKICB4bGltKDEsIDE0KSArCiAgbGFicyh4ID0gIlRpbWUgKGRheXMpIiwgeSA9ICJDb21wZXRpbmcgY3VlcyIsIGZpbGwgPSAiUkJDIikgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG9wdGlvbiA9ICJDIikgKwogIHRoZW1lX2J3KCkrCiAgdGhlbWUoYXhpcy50aXRsZS54PWVsZW1lbnRfYmxhbmsoKSkKCiMgcGxvdHRpbmcgSSAKUl9JLnBsIDwtIFJfc3RhdGljLmR5bjIgJT4lIAogIGZpbHRlcih2YXJpYWJsZSA9PSAiSTEiKSAlPiUgCmdncGxvdChhZXMoeCA9IHRpbWUsIHkgPSBsYWJlbF9jaSwgZmlsbCA9IHZhbHVlKSkgKwogIGdlb21fcmFzdGVyKCkgKwogIHhsaW0oMSwgMTQpICsKICBsYWJzKHggPSAiVGltZSAoZGF5cykiLCB5ID0gIkNvbXBldGluZyBjdWVzIiwgZmlsbCA9ICJBc2V4dWFsIGlSQkMiKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2Mob3B0aW9uID0gIkEiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50aXRsZS54PWVsZW1lbnRfYmxhbmsoKSkKCiMgcGxvdHRpbmcgdGF1ClJfdGF1LnBsIDwtIFJfc3RhdGljLmR5bjIgJT4lIAogIGZpbHRlcih2YXJpYWJsZSA9PSAidGF1MSIpICU+JSAKZ2dwbG90KGFlcyh4ID0gdGltZSwgeSA9IGxhYmVsX2NpLCBmaWxsID0gdmFsdWUpKSArCiAgZ2VvbV9yYXN0ZXIoKSArCiAgeGxpbSgxLCAxNCkgKwogIGxhYnMoeCA9ICJUaW1lIChkYXlzKSIsIHkgPSAiQ29tcGV0aW5nIGN1ZXMiLCBmaWxsID0gIlRyYW5zbWlzc2lvblxucG90ZW50aWFsIikgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG9wdGlvbiA9ICJCIikgKwogIHRoZW1lX2J3KCkgCgpSX2R5bi5wbCA8LSBnZ2FycmFuZ2UoUl9jci5wbCwgUl9JLnBsLCBSX1IucGwsIFJfdGF1LnBsLCBuY29sID0gMSwgYWxpZ24gPSAidiIpCmBgYAoKIyBwbG90IHRvZ2V0aGVyCmBgYHtyfQpnZ2FycmFuZ2UoR2xvZ19keW4ucGwsIFJfZHluLnBsLCBuY29sID0gMiwgbGFiZWxzID0gYygiQSIsICJCIiksIGFsaWduID0gImgiKQpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby9zdGF0aWNfZHluLnRpZmYiKSwgdW5pdHMgPSAicHgiLCB3aWR0aCA9IDIyMDAsIGhlaWdodCA9IDIwMDAsIHNjYWxlID0gMS4yLCBkcGk9MzAwLCAgYmcgPSAid2hpdGUiKQpgYGAKCgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIyBpbnZhc2lvbiBhbmFseXNpcwojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIyBpbXBvcnQgaW4gZGF0YSAoYWxyZWFkeSAyMCBkYXlzICkKYGBge3J9CmludmFkZS5kZiA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2NpX2ludmFzaW9uLmNzdiIpKQpgYGAKCgojIHByb2Nlc3MgZGF0YSBmb3IgaW52YXNpb24gbWF0cml4CmBgYHtyfQppbnZhZGUubWF0IDwtIGludmFkZS5kZiAlPiUgCiAgZ3JvdXBfYnkoVjEgPSBwbWluKG11dF9pZCwgcmVzX2lkKSwgVjIgPSBwbWF4KG11dF9pZCwgcmVzX2lkKSkgJT4lICMgZ3JvdXAgYnkgY3VlIGNvbXBldGl0aW9uLCBpcnJlZ2FyZGxlc3Mgb2Ygb3JkZXIKICBtdXRhdGUoaWRfYWx0ID0gcGFzdGUwKFYxLCBWMiksCiAgICAgICAgIGludmFkZSA9IGNhc2Vfd2hlbigKICAgICAgICAgICBmaXRuZXNzID4gMCB+ICJpbnZhZGUiLAogICAgICAgICAgIGZpdG5lc3MgPCAwIH4gIm5vdCBpbnZhZGUiCiAgICAgICAgICkpICU+JSAKICBncm91cF9ieShpZF9hbHQpICU+JSAKICBtdXRhdGUoCiAgICBtdXRfaXNfVjEgPSBjYXNlX3doZW4oCiAgICBtdXRfaWQgPT0gVjEgfiAiVjFfaW52YWRlIiwKICAgIG11dF9pZCAhPSBWMSB+ICJWMV9pbnZhZGVkIikpICU+JSAKICBhcnJhbmdlKGlkX2FsdCkgJT4lIAogIHNlbGVjdChmaXRuZXNzLCBWMSwgVjIsIGlkX2FsdCwgaW52YWRlLCBtdXRfaXNfVjEpICU+JSAKICB0aWR5cjo6cGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IG11dF9pc19WMSwgdmFsdWVzX2Zyb20gPSBmaXRuZXNzKSAlPiUgCiAgZ3JvdXBfYnkoaWRfYWx0KSAlPiUgCiAgbXV0YXRlKFYxX2ludmFkZTIgPSBnc3ViKCJOQSIsICIiLCBwYXN0ZTAoVjFfaW52YWRlLCBjb2xsYXBzZSA9ICIiKSksCiAgICAgICAgIFYxX2ludmFkZWQyID0gZ3N1YigiTkEiLCAiIiwgcGFzdGUwKFYxX2ludmFkZWQsIGNvbGxhcHNlID0gIiIpKSkgJT4lIAogIGRpc3RpbmN0KGlkX2FsdCwgLmtlZXBfYWxsID0gVCkgJT4lIAogIG11dGF0ZSgKICAgIGNhdGVnb3J5ID0gY2FzZV93aGVuKAogICAgVjFfaW52YWRlMiA+IDAgJiBWMV9pbnZhZGVkMiA+IDAgfiAiTXV0dWFsIGludmFzaW9uIiwKICAgIFYxX2ludmFkZTIgPiAwICYgVjFfaW52YWRlZDIgPCAwIH4gIk9ubHkgc3RyYWluIDEgaW52YXNpb24iLAogICAgVjFfaW52YWRlMiA8IDAgJiBWMV9pbnZhZGVkMiA+IDAgfiAiT25seSBzdHJhaW4gMiBpbnZhc2lvbiIsCiAgICBWMV9pbnZhZGUyIDwgMCAmIFYxX2ludmFkZWQyIDwgMCB+ICJNdXR1YWwgbm9uLWludmFzaW9uIgogICkpICU+JSAKICBzZWxlY3QoVjEsIFYyLCBpbnZhc2lvbiA9IGNhdGVnb3J5KQoKaW52YWRlLmRmICU+JSBmaWx0ZXIobXV0X2lkID09ICJHLWlfbm9uZSIpCmludmFkZS5kZiAlPiUgZmlsdGVyKHJlc19pZCA9PSAiRy1pX25vbmUiKQpgYGAKCgpgYGB7cn0KIyBmb3IgcGxvdHRpbmcsIG5lZWQgdG8gZ2V0IGFsbCBzYW1lIGN1ZSB2cyBzYW1lIGN1ZSwgd2hpY2ggd2Ugd2lsbCBzZXQgdG8gTkEKaW52YWRlLk5BIDwtIGNiaW5kLmRhdGEuZnJhbWUoYFYxYCA9IHVuaXF1ZShpbnZhZGUubWF0JFYxKSwKICAgICAgYFYyYCA9IHVuaXF1ZShpbnZhZGUubWF0JFYxKSwKICAgICAgaW52YXNpb24gPSBOQSkKCmludmFkZS5tYXQyIDwtIHJiaW5kKGludmFkZS5tYXQsIGludmFkZS5OQSkKCiMgZ2V0IGxhYmVsCmludmFkZS5tYXQzIDwtIGludmFkZS5tYXQyICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGV6X2xhYmVsLCBpZF9jaSwgVjFfbGFiZWwgPSBsYWJlbF9jaSksIGJ5ID0gYygiVjEiID0gImlkX2NpIikpICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGV6X2xhYmVsLCBpZF9jaSwgVjJfbGFiZWwgPSBsYWJlbF9jaSksIGJ5ID0gYygiVjIiID0gImlkX2NpIikpICU+JSAKICBtdXRhdGUoVjFfbGFiZWwgPSBnc3ViKCJsb2ciLCAibG9nMTAiLCBWMV9sYWJlbCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVjJfbGFiZWwgPSBnc3ViKCJsb2ciLCAibG9nMTAiLCBWMl9sYWJlbCkpCgoKaW52YWRlLm1hdDQgPC0gcmJpbmQoCiAgc2VsZWN0KGludmFkZS5tYXQzLCBWMV9sYWJlbCwgVjJfbGFiZWwsIGludmFzaW9uKSwKICBzZWxlY3QoaW52YWRlLm1hdDMsIFYyX2xhYmVsID0gVjFfbGFiZWwsIFYxX2xhYmVsID0gVjJfbGFiZWwpICU+JSBtdXRhdGUoaW52YXNpb24gPSBOQSkpICU+JQogIG11dGF0ZSgKICAgIGludmFzaW9uXzIgPSBjYXNlX3doZW4oCiAgICBpbnZhc2lvbiA9PSAiTXV0dWFsIGludmFzaW9uIiB+ICJNdXR1YWwgaW52YXNpb24iLAogICAgaW52YXNpb24gPT0gIk9ubHkgc3RyYWluIDEgaW52YXNpb24iIH4gIkNvbXBldGl0aXZlIGV4Y2x1c2lvblxub2YgYW5vdGhlciBjdWUiLAogICAgaW52YXNpb24gPT0gIk9ubHkgc3RyYWluIDIgaW52YXNpb24iIH4gIkNvbXBldGl0aXZlIGV4Y2x1c2lvblxuYnkgYW5vdGhlciBjdWUiCiAgKSkgJT4lIAogIGZpbHRlcighaXMubmEoVjFfbGFiZWwpKQoKaW52YWRlLm1hdDQkVjFfbGFiZWwgPC0gZmFjdG9yKGludmFkZS5tYXQ0JFYxX2xhYmVsLCBsZXZlbHMgPSAgYygiRyBsb2cxMCIsICJHIiwgIkcxK0cyIiwgIkkgbG9nMTAiLCAiSSIsICJJK0lnIGxvZzEwIiwgIkkrSWciLCAiSTErSTIgbG9nMTAiLCAiSTErSTIiLCAiSWcgbG9nMTAiLCAiSWciLCAiSWcxK0lnMiIsICJSIGxvZzEwIiwgIlIiLCAic3VtIGxvZzEwIiwgInN1bSIpKQppbnZhZGUubWF0NCRWMl9sYWJlbCA8LSBmYWN0b3IoaW52YWRlLm1hdDQkVjJfbGFiZWwsIGxldmVscyA9ICBjKCJHIiwgIkcxK0cyIiwgIkkgbG9nMTAiLCAiSSIsICJJK0lnIGxvZzEwIiwgIkkrSWciLCAiSTErSTIgbG9nMTAiLCAiSTErSTIiLCAiSWcgbG9nMTAiLCAiSWciLCAiSWcxK0lnMiIsICJSIGxvZzEwIiwgIlIiLCAic3VtIGxvZzEwIiwgInN1bSIsICJHIGxvZzEwIikpCmBgYAoKCiMgcGxvdCBpbnZhc2lvbiBtYXRyaXgKYGBge3J9CmludmFzaW9uLnBsMSA8LSBnZ3Bsb3QoZGF0YSA9IGludmFkZS5tYXQ0LCBhZXMoeCA9IFYyX2xhYmVsLCB5ID0gVjFfbGFiZWwsIGZpbGwgPSBpbnZhc2lvbl8yKSkgKwogIGdlb21fdGlsZShjb2xvciA9ICJibGFjayIpICsKICB0aGVtZV9taW5pbWFsKCkgKyAgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwKICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCB2anVzdCA9IDEsIGhqdXN0ID0gMSksCiAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksCiAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksCiAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICBwbG90Lm1hcmdpbj1tYXJnaW4ociA9IDApKSArIAogIGxhYnMoZmlsbCA9ICJJbnZhc2liaWxpdHkiLCB4ID0gIkNvbXBldGluZyBjdWUiLCB5ID0gIlJlZmVyZW5jZSBjdWUiKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSByZXYpICsKICBzY2FsZV95X2Rpc2NyZXRlKGxpbWl0cyA9IHJldikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIkNvbXBldGl0aXZlIGV4Y2x1c2lvblxub2YgYW5vdGhlciBjdWUiID0gIiM0NTc1YjQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNvbXBldGl0aXZlIGV4Y2x1c2lvblxuYnkgYW5vdGhlciBjdWUiID0gIiNmYzhkNTkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk11dHVhbCBpbnZhc2lvbiIgPSAiI2ZlZTA5MCIpLAogICAgICAgICAgICAgICAgICAgIG5hLnZhbHVlID0gIndoaXRlIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgojIGNyZWF0ZSBzdW1tYXJ5IGJhciBjaGFydApgYGB7cn0KIyBjcmVhdGUgYSBzdGFja2VkIGJhcmNoYXJ0IGZvciBzdW1tYXJ5CiMjIGZpbHRlciBvdXQgbmEKaW52YWRlLm1hdGFsdCA8LSBpbnZhZGUubWF0MyAlPiUgbmEuZXhjbHVkZSgpCgojIGdldCBmcnF1ZW5jeSBmcm9tIGJvdGggc2lkZXMuIE5vdGUgd2hlbiBncm91cGluZyBmb3IgVjIsIGZyb20gdGhlIHBlcnNwZWN0aXZlIG9mIGN1ZSAyLCBzY2VuYXJyaW8gd2hlbiBzdHJhaW4gMiBpbnZhZGUgPSBzdHJhaW4gMSBpbnZhZGUKaW52YWRlLm1hdGFsdDEgPC0gaW52YWRlLm1hdGFsdCAlPiUgZ3JvdXBfYnkoVjFfbGFiZWwsIGludmFzaW9uKSAlPiUgCiAgc3VtbWFyaXplKGZyZXF1ZW5jeV8xID0gbigpKQoKaW52YWRlLm1hdGFsdDIgPC0gaW52YWRlLm1hdGFsdCAlPiUKICBtdXRhdGUoaW52YXNpb25fYWx0ID0gY2FzZV93aGVuKAogICAgaW52YXNpb24gPT0gIk9ubHkgc3RyYWluIDEgaW52YXNpb24iIH4gIk9ubHkgc3RyYWluIDIgaW52YXNpb24iLAogICAgaW52YXNpb24gPT0gIk9ubHkgc3RyYWluIDIgaW52YXNpb24iIH4gIk9ubHkgc3RyYWluIDEgaW52YXNpb24iLAogICAgaW52YXNpb24gPT0gIk11dHVhbCBpbnZhc2lvbiIgfiAiTXV0dWFsIGludmFzaW9uIiwKICAgIGludmFzaW9uID09ICJNdXR1YWwgbm9uLWludmFzaW9uIiB+ICJNdXR1YWwgbm9uLWludmFzaW9uIgogICkpICU+JSAKICBncm91cF9ieShWMl9sYWJlbCwgaW52YXNpb25fYWx0KSAlPiUgCiAgc3VtbWFyaXplKGZyZXF1ZW5jeV8yID0gbigpKSAgICAgCgojIGZ1bGwgam9pbiBhbmQgc3VtLiBoYXMgY29uZmlybWVkIGFsbCBvZiB0aGVtIGFkZCB1cCB0byAxNCAKaW52YWRlLm1hdGFsdDMgPC0gZnVsbF9qb2luKGludmFkZS5tYXRhbHQxLCBpbnZhZGUubWF0YWx0MiwgYnkgPSBjKCJWMV9sYWJlbCIgPSAiVjJfbGFiZWwiLCAiaW52YXNpb24iID0gImludmFzaW9uX2FsdCIpKQoKaW52YWRlLm1hdGFsdDNbaXMubmEoaW52YWRlLm1hdGFsdDMpXSA8LSAwCmludmFkZS5tYXRhbHQ0IDwtIGludmFkZS5tYXRhbHQzICU+JSAKICBtdXRhdGUoZnJlcSA9IGZyZXF1ZW5jeV8xICsgZnJlcXVlbmN5XzIpICU+JSAKICBtdXRhdGUodGVtcCA9IGNhc2Vfd2hlbigKICAgIGludmFzaW9uID09ICJPbmx5IHN0cmFpbiAxIGludmFzaW9uIiB+IGZyZXEKICApKSAlPiUgCiAgZ3JvdXBfYnkoVjFfbGFiZWwpICU+JSAKICBtdXRhdGUoaW52YWRlXzFfZnJlcSA9IG1heCh0ZW1wLCBuYS5ybSA9IFQpKSAlPiUgCiAgbXV0YXRlKGludmFzaW9uXzIgPSBjYXNlX3doZW4oCiAgICBpbnZhc2lvbiA9PSAiTXV0dWFsIGludmFzaW9uIiB+ICJNdXR1YWwgaW52YXNpb24iLAogICAgaW52YXNpb24gPT0gIk9ubHkgc3RyYWluIDEgaW52YXNpb24iIH4gIkNvbXBldGl0aXZlIGV4Y2x1c2lvblxub2YgYW5vdGhlciBjdWUiLAogICAgaW52YXNpb24gPT0gIk9ubHkgc3RyYWluIDIgaW52YXNpb24iIH4gIkNvbXBldGl0aXZlIGV4Y2x1c2lvblxuYnkgYW5vdGhlciBjdWUiCiAgKSkKYGBgCgoKCmBgYHtyfQppbnZhc2lvbi5wbDIgPC0gZ2dwbG90KCkgKwogIGdlb21fYmFyKGRhdGEgPSBpbnZhZGUubWF0YWx0NCwgYWVzKHggPSBmcmVxLCB5ID0gcmVvcmRlcihWMV9sYWJlbCwgaW52YWRlXzFfZnJlcSksIGZpbGwgPSBmb3JjYXRzOjpmY3RfcmV2KGZhY3RvcihpbnZhc2lvbl8yLCBsZXZlbHMgPSBjKCJDb21wZXRpdGl2ZSBleGNsdXNpb25cbm9mIGFub3RoZXIgY3VlIiwgIkNvbXBldGl0aXZlIGV4Y2x1c2lvblxuYnkgYW5vdGhlciBjdWUiLCAiTXV0dWFsIGludmFzaW9uIiwgIk11dHVhbCBub24taW52YXNpb24iKSkpKSwgc3RhdCA9ICJpZGVudGl0eSIpICsKICBsYWJzKHggPSAiRnJlcXVlbmN5IiwgZmlsbCA9ICJJbnZhc2liaWxpdHkiLCB5ID0gIkN1ZSIpICsKICB0aGVtZV9idygpICArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiQ29tcGV0aXRpdmUgZXhjbHVzaW9uXG5vZiBhbm90aGVyIGN1ZSIgPSAiIzQ1NzViNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ29tcGV0aXRpdmUgZXhjbHVzaW9uXG5ieSBhbm90aGVyIGN1ZSIgPSAiI2ZjOGQ1OSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTXV0dWFsIGludmFzaW9uIiA9ICIjZmVlMDkwIikpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSkpCmBgYAoKIyBwbG90IHRvZ2V0aGVyCmBgYHtyfQpnZ2FycmFuZ2UoaW52YXNpb24ucGwxLCBpbnZhc2lvbi5wbDIsIGFsaWduID0gImgiLCBjb21tb24ubGVnZW5kID0gVCwgd2lkdGhzID0gYygyLCAxKSkKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vaW52YXNpb25fYS50aWZmIiksIHVuaXRzID0gInB4Iiwgd2lkdGggPSAyMjUwLCBoZWlnaHQgPSAxMTAwLCBzY2FsZSA9IDEuNCwgZHBpPTMwMCwgIGJnID0gIndoaXRlIikKYGBgCgojLS0tLS0tLS0tLS0tLS0tLSBpbnZhc2lvbiBwYWlyd2lzZSBjb21wYXJpc29uLS0tLS0tLS0tLS0tLS0tLS0jCiMjIHByb2NlcyBkYXRhCmBgYHtyfQojIGpvaW4gaW52YWRlIGRmIHdpdGggbGFiZWwgYmVjYXVzZSBJIGFtIGxhenkKaW52YWRlLmRmMiA8LSBpbnZhZGUuZGYgJT4lIAogIGxlZnRfam9pbihzZWxlY3QoZXpfbGFiZWwsIGlkX2NpLCBsYWJlbF9jaV8xID0gbGFiZWxfY2kpLCBieSA9IGMoIm11dF9pZCIgPSAiaWRfY2kiKSkKCmludmFkZS5kZjIgCmBgYAoKIyBsb2cKYGBge3J9CiMgZ2V0IG5vbi1sb2dnZWQgcGFpcmluZ3MKaW52YWRlX25vbG9nIDwtIGludmFkZS5kZjIgJT4lIAogIG11dGF0ZShjdWVfMSA9IHRyaW13cyhnc3ViKCJcXCAuKiIsICIiLCBsYWJlbF9jaV8xKSksCiAgICAgICAgIGxvZ18xID0gY2FzZV93aGVuKAogICAgICAgICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgImxvZyIpIH4gImxvZyIsCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIiwgbmVnYXRlID0gVCkgfiAibm9uZSIpKSAlPiUgCiAgZmlsdGVyKGxvZ18xID09ICJub25lIikKCgppbnZhZGVfbG9nIDwtIGludmFkZS5kZjIgJT4lIAogIG11dGF0ZShjdWVfMSA9IHRyaW13cyhnc3ViKCJcXCAuKiIsICIiLCBsYWJlbF9jaV8xKSksCiAgICAgICAgIGxvZ18xID0gY2FzZV93aGVuKAogICAgICAgICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgImxvZyIpIH4gImxvZyIsCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIiwgbmVnYXRlID0gVCkgfiAibm9uZSIpKSAlPiUgCiAgZmlsdGVyKGxvZ18xID09ICJsb2ciKQoKaW52YWRlX2xvZy5kZiA8LSBsZWZ0X2pvaW4oCiAgc2VsZWN0KGludmFkZV9ub2xvZywgY3VlXzEsIHJlc19pZCwgbG9nXzEsIE5vbmUgPSBmaXRuZXNzKSwKICBzZWxlY3QoaW52YWRlX2xvZywgY3VlXzEsIHJlc19pZCwgbG9nXzEsIExvZyA9IGZpdG5lc3MpLAogIGJ5ID0gYygiY3VlXzEiLCAicmVzX2lkIikpICU+JSAKICBmaWx0ZXIoIWlzLm5hKE5vbmUpICYgIWlzLm5hKExvZykpICU+JSAKICBtdXRhdGUoY2xhc3NpZmljYXRpb24gPSBpZmVsc2UoTG9nID4gTm9uZSwgIkxvZ2dlZCBiZXR0ZXIiLCAiTm90IGxvZ2dlZCBiZXR0ZXIiKSkKCmludmFkZV9sb2cKYGBgCgojIGNvbWJpbmVkCmBgYHtyfQppbnZhZGVfbm9jb21iIDwtIGludmFkZS5kZjIgJT4lIAogIG11dGF0ZShjdWVfMSA9IGlmZWxzZSgKICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgInN1bSIpLCAiSStJZyIsCiAgICB0cmltd3MoZ3N1YigiKzEuKnxcXCBsb2ciLCAiIiwgbGFiZWxfY2lfMSkpCiAgKSwKICBsb2dfMSA9IGNhc2Vfd2hlbigKICAgICAgICAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICJsb2ciKSB+ICJsb2ciLAogICAgICAgICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgImxvZyIsIG5lZ2F0ZSA9IFQpIH4gIm5vbmUiKSwKICAgIGNvbWJfMSA9IGNhc2Vfd2hlbigKICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgIjErfHN1bSIpIH4gImNvbWIiLAogICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAiMSt8c3VtIiwgbmVnYXRlID0gVCkgfiAibm9uZSIgCiAgKSkgJT4lIAogIGZpbHRlcihjb21iXzEgPT0gIm5vbmUiKQoKaW52YWRlX2NvbWIgPC0gaW52YWRlLmRmMiAlPiUgCiAgbXV0YXRlKGN1ZV8xID0gaWZlbHNlKAogICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAic3VtIiksICJJK0lnIiwKICAgIHRyaW13cyhnc3ViKCIrMS4qfFxcIGxvZyIsICIiLCBsYWJlbF9jaV8xKSkKICApLAogIGxvZ18xID0gY2FzZV93aGVuKAogICAgICAgICAgIHN0cl9kZXRlY3QobGFiZWxfY2lfMSwgImxvZyIpIH4gImxvZyIsCiAgICAgICAgICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAibG9nIiwgbmVnYXRlID0gVCkgfiAibm9uZSIpLAogICAgY29tYl8xID0gY2FzZV93aGVuKAogICAgc3RyX2RldGVjdChsYWJlbF9jaV8xLCAiMSt8c3VtIikgfiAiY29tYiIsCiAgICBzdHJfZGV0ZWN0KGxhYmVsX2NpXzEsICIxK3xzdW0iLCBuZWdhdGUgPSBUKSB+ICJub25lIiAKICApKSAlPiUgCiAgZmlsdGVyKGNvbWJfMSA9PSAiY29tYiIpCiAgCmludmFkZV9jb21iLmRmIDwtIGxlZnRfam9pbigKICBzZWxlY3QoaW52YWRlX25vY29tYiwgY3VlXzEsIHJlc19pZCwgbG9nXzEsIFNlbGYgPSBmaXRuZXNzKSwKICBzZWxlY3QoaW52YWRlX2NvbWIsIGN1ZV8xLCByZXNfaWQsIGxvZ18xLCBUb3RhbCA9IGZpdG5lc3MpLAogIGJ5ID0gYygiY3VlXzEiLCAibG9nXzEiLCAicmVzX2lkIikpICU+JSAKICBmaWx0ZXIoIWlzLm5hKFRvdGFsKSAmICFpcy5uYShTZWxmKSkgJT4lIAogIG11dGF0ZShjbGFzc2lmaWNhdGlvbiA9IGlmZWxzZShUb3RhbCA+IFNlbGYsICJUb3RhbCBiZXR0ZXIiLCAiU2VsZiBiZXR0ZXIiKSkKaW52YWRlX2NvbWIuZGYKYGBgCgojIHBsb3QKYGBge3J9CmludmFkZV9sb2cucGwgPC0gZ2dwYWlyZWQoaW52YWRlX2xvZy5kZiwgY29uZDEgPSAiTm9uZSIsIGNvbmQyID0gIkxvZyIsIGxpbmUuY29sb3IgPSAiY2xhc3NpZmljYXRpb24iLCBhbHBoYSA9IDAuNSkgKwogIGxhYnMoeCA9ICJDdWUgcGVyY2VwdGlvbiIsIHkgPSAiRml0bmVzcyBkaWZmZXJlbmNlIiwgY29sb3IgPSAiRWZmZWN0IikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJOb3QgbG9nZ2VkIGJldHRlciIgPSAiI2ZjOGQ1OSIsICJMb2dnZWQgYmV0dGVyIiA9ICIjNDU3NWI0IikpKwogIHN0YXRfY29tcGFyZV9tZWFucyhwYWlyZWQgPSBUUlVFLCBoanVzdCA9IC0wKQoKaW52YWRlX2NvbWIucGwgPC0gZ2dwYWlyZWQoaW52YWRlX2NvbWIuZGYsIGNvbmQxID0gIlRvdGFsIiwgY29uZDIgPSAiU2VsZiIsIGxpbmUuY29sb3IgPSAiY2xhc3NpZmljYXRpb24iLCBhbHBoYSA9IDAuNSkgKwogIGxhYnMoeCA9ICJDdWUgcGVyY2VwdGlvbiIsIHkgPSAiRml0bmVzcyBkaWZmZXJlbmNlIiwgY29sb3IgPSAiRWZmZWN0IikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJUb3RhbCBiZXR0ZXIiID0gIiNmYzhkNTkiLCAiU2VsZiBiZXR0ZXIiID0gIiM0NTc1YjQiKSkrCiAgc3RhdF9jb21wYXJlX21lYW5zKHBhaXJlZCA9IFRSVUUsIGhqdXN0ID0gLTApCgpnZ2FycmFuZ2UoaW52YWRlX2xvZy5wbCwgaW52YWRlX2NvbWIucGwsIGFsaWduID0gImgiLCBuY29sID0gMikKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vaW52YXNpb25fYi50aWZmIiksIHVuaXRzID0gInB4Iiwgd2lkdGggPSAyMjUwLCBoZWlnaHQgPSA5MDAsIHNjYWxlID0gMS4yLCBkcGk9MzAwLCAgYmcgPSAid2hpdGUiKQpgYGAKCgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKIyBDdWUgcGVyZm9ybWFuY2UgYWNyb3NzIHNpbmdsZSwgY28taW5mZWN0aW9uLCBzdGF0aWMsIGFuZCBpbnZhc2lvbgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSMKYGBge3J9CiMgaW1wb3J0IGluIGFsbCB0aGUgcmFua3MKc2lfb3B0LmRmIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvc2lfb3B0LmNzdiIpKQpjaV9vcHQuZGYgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9jaV9vcHQuY3N2IikpCnN0YXRpYy5kZiA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2NpX3N0YXRpYy5jc3YiKSkKaW52YXNpb24uZGYgPC0gcmVhZC5jc3YoaGVyZSgiZGF0YS9jaV9pbnZhc2lvbi5jc3YiKSkKCiMgY2FsY3VsYXRlIG1lYW4gZml0bmVzcwpzdGF0aWMubWVhbiAjIyBhbHJlYWR5IGNhbGN1bGF0ZWQKaW52YXNpb24ubWVhbiA8LSByYmluZChzZWxlY3QoaW52YXNpb24uZGYsIGN1ZSA9IG11dF9pZCwgZml0bmVzcyksCiAgICAgIHNlbGVjdChpbnZhc2lvbi5kZiAlPiUgbXV0YXRlKGZpdG5lc3MyID0gZml0bmVzcyAqIC0xKSwgY3VlID0gcmVzX2lkLCBmaXRuZXNzID0gZml0bmVzczIpKSAlPiUgCiAgZ3JvdXBfYnkoY3VlKSAlPiUgCiAgc3VtbWFyaXplKG1lYW5fZml0bmVzcyA9IG1lYW4oZml0bmVzcykpICU+JSAKICBhcnJhbmdlKGRlc2MobWVhbl9maXRuZXNzKSkKCiMgY2FsY3VsYXRlIHJhbmtzCnNpLnJhbmsgPC0gc2lfb3B0LmRmICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGV6X2xhYmVsLCBpZF9jaSwgaWRfc2ksIGxhYmVsID0gZXpfbGFiZWxfc2kpLCBieSA9IGMoImlkIiA9ICJpZF9zaSIpKSAlPiUgCiAgbXV0YXRlKHJhbmsgPSBkZW5zZV9yYW5rKC1maXRuZXNzXzIwKSwKICAgICAgICAgbW9kZWwgPSAiU2luZ2xlIGluZmVjdGlvbiIpICU+JSAKICBzZWxlY3QocmFuaywgbW9kZWwsIGlkID0gaWRfY2ksIGxhYmVsKQoKY2kucmFuayA8LSBjaV9vcHQuZGYgJT4lIAogIGxlZnRfam9pbihzZWxlY3QoY2lfZml0bmVzcy5kZiwgdmFsdWUsIGxhYmVsKSwgYnkgPSAibGFiZWwiKSAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChlel9sYWJlbCwgaWRfY2ksIGlkX3NpLCBlel9sYWJlbCksIGJ5ID0gYygiaWQiID0gImlkX2NpIikpICU+JSAKICBtdXRhdGUocmFuayA9IHJhbmsoLXZhbHVlKSwKICAgICAgICAgbW9kZWwgPSAiQ28taW5mZWN0aW9uIikgJT4lIAogIHNlbGVjdChyYW5rLCBtb2RlbCwgaWQsIGxhYmVsID0gZXpfbGFiZWwpCgpzdGF0aWMucmFuayA8LSBzdGF0aWMubWVhbiAlPiUgCiAgbXV0YXRlKGxhYmVsX2NpID0gZ3N1YigibG9nMTAiLCAibG9nIiwgbGFiZWxfY2lfMSkpICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGV6X2xhYmVsLCBpZF9jaSwgbGFiZWxfY2ksIGV6X2xhYmVsKSwgYnkgPSBjKCJsYWJlbF9jaSIgPSAibGFiZWxfY2kiKSkgJT4lIAogIG11dGF0ZShyYW5rID0gcmFuaygtbWVhbl9maXRuZXNzKSwKICAgICAgICAgbW9kZWwgPSAiU3RhdGljIG1peGVkIGdlbm90eXBlIikgJT4lIAogIHNlbGVjdChyYW5rLCBtb2RlbCwgaWQgPSBpZF9jaSwgbGFiZWwgPSBlel9sYWJlbCkKCmludmFzaW9uLnJhbmsgPC0gaW52YXNpb24ubWVhbiAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChlel9sYWJlbCwgaWRfY2ksIGV6X2xhYmVsKSwgYnkgPSBjKCJjdWUiID0gImlkX2NpIikpICU+JSAKICBtdXRhdGUocmFuayA9IHJhbmsoLW1lYW5fZml0bmVzcyksCiAgICAgICAgIG1vZGVsID0gIkludmFzaXZlIG1peGVkIGdlbm90eXBlIikgJT4lIAogIHNlbGVjdChyYW5rLCBtb2RlbCwgaWQgPSBjdWUsIGxhYmVsID0gZXpfbGFiZWwpICU+JSAKICBtdXRhdGUobGFiZWwgPSBnc3ViKCJcbiIsICIgIiwgcGFzdGUwKCIgICAiLCBsYWJlbCkpKQoKc3RhdGljLnJhbmsKIyBjb25jYXRlbmF0ZQpmaXRuZXNzLnJhbmsgPC0gcmJpbmQoCiAgc2kucmFuaywgY2kucmFuaywgc3RhdGljLnJhbmssIGludmFzaW9uLnJhbmsKKSAlPiUgCiAgbXV0YXRlKG1vZGVsID0gZmN0X3JlbGV2ZWwobW9kZWwsIGMoIlNpbmdsZSBpbmZlY3Rpb24iLCAiQ28taW5mZWN0aW9uIiwgIlN0YXRpYyBtaXhlZCBnZW5vdHlwZSIsICJJbnZhc2l2ZSBtaXhlZCBnZW5vdHlwZSIpKSkKCiMgaGlnaGxpZ2h0IHRoZSBnb29kIG9uZXMKZml0bmVzcy5yYW5rX2dvb2QgPC0gZml0bmVzcy5yYW5rICU+JSAKICBmaWx0ZXIoaWQgJWluJSBjKCJJZy1pX2xvZyIsICJJLWkrSWctaV9sb2ciLCAic3VtX2xvZyIsICJHLWlfbG9nIikpCmBgYAoKIyBwbG90CmBgYHtyfQpsaWJyYXJ5KGdnYnVtcCkKCmdncGxvdCgpICsKICBnZW9tX2J1bXAoZGF0YSA9IGZpdG5lc3MucmFuaywgYWVzKHggPSBtb2RlbCwgeSA9IHJhbmssIGdyb3VwID0gaWQpLCBjb2xvciA9ICJncmV5IikgKwogIGdlb21fcG9pbnQoZGF0YSA9IGZpdG5lc3MucmFuaywgYWVzKHggPSBtb2RlbCwgeSA9IHJhbmssIGdyb3VwID0gaWQpLCBjb2xvciA9ICJncmV5Iiwgc2l6ZSA9IDMpICsKICBnZW9tX2J1bXAoZGF0YSA9IGZpdG5lc3MucmFua19nb29kLCBhZXMoeCA9IG1vZGVsLCB5ID0gcmFuaywgZ3JvdXAgPSBpZCwgY29sb3IgPSBpZCkpICsKICBnZW9tX3BvaW50KGRhdGEgPSBmaXRuZXNzLnJhbmtfZ29vZCwgYWVzKHggPSBtb2RlbCwgeSA9IHJhbmssIGdyb3VwID0gaWQsIGNvbG9yID0gaWQpLCBzaXplID0gMykgKwogIGdlb21fdGV4dChkYXRhID0gaW52YXNpb24ucmFuaywgYWVzKHggPSBtb2RlbCwgeSA9IHJhbmssIGxhYmVsID0gbGFiZWwpLCBzaXplID0gMy41LCBoanVzdCA9IDAsIGluaGVyaXQuYWVzID0gRikgKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZCgpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGNvb3JkX2NhcnRlc2lhbihjbGlwID0gIm9mZiIpICsKICBzY2FsZV95X3JldmVyc2UoKSArCiAgZXhwYW5kX2xpbWl0cyh4ID0gNS41KSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgbGFicyh4ID0gIk1vZGVsIiwgeSA9ICJNZWFuIGZpdG5lc3MgcmFuayIpCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3Bsb3MtYmlvL2ZpdG5lc3NfcmFuay50aWZmIiksIHVuaXRzID0gInB4Iiwgd2lkdGggPSAyMjUwLCBoZWlnaHQgPSAxNTAwLCBzY2FsZSA9IDEsIGRwaT0zMDAsICBiZyA9ICJ3aGl0ZSIpCmBgYAoKCiMtPT09PT09PT09PT09PT09PT09PT09IwojIFBhcnRpdGlvbmluZyBiZXN0IGN1ZQojPT09PT09PT09PT09PT09PT09PT09LSMKIy0tLS0tLS0gc2luZ2xlIGluZmVjdGlvbiAtLS0tLS0tLS0tLSMKIyByZWRvIHNvbWUgb3B0aW1pemF0aW9uIChsb3dlciBmaXRuZXNzIGluIG5vIFIgdGhhbiBkZWZhdWx0KQpgYGB7cn0Kc291cmNlKGhlcmUoImZ1bmN0aW9ucy9jaGFiYXVkaV9zaV9jbGVhbl9SLlIiKSkKc291cmNlKGhlcmUoImZ1bmN0aW9ucy9jaGFiYXVkaV9zaV9jbGVhbl9OLlIiKSkKIyBJIG5vbmUKY2wgPC0gbWFrZUNsdXN0ZXIoZGV0ZWN0Q29yZXMoKSk7IHNldERlZmF1bHRDbHVzdGVyKGNsID0gY2wpCklfbm9fUiA8LSBvcHRpbVBhcmFsbGVsKAogICAgcGFyID0gcmVwKDAuNSw0KSwgIyBzdGFydCBhdCAwLjV4NAogICAgZm4gPSBjaGFiYXVkaV9zaV9jbGVhbl9SLCAKICAgIGNvbnRyb2wgPSBsaXN0KHRyYWNlID0gNiwgZm5zY2FsZSA9IC0xKSwKICAgIGltbXVuaXR5ID0gInRzdWt1c2hpIiwKICAgIHBhcmFtZXRlcnMgPSBwYXJhbWV0ZXJzX3RzdWt1c2hpLAogICAgdGltZV9yYW5nZSA9IHNlcSgwLCAyMCwgYnkgPSAxZS0zKSwKICAgIGN1ZV9yYW5nZSA9ICBzZXEoMCwgNiooMTBeNiksIGJ5ID0gKDYqKDEwXjYpKS81MDAwKSwKICAgIGN1ZSA9ICJJIiwKICAgIGxvZ19jdWUgPSAibm9uZSIsCiAgICBzb2x2ZXIgPSAidm9kZSIpCnN0b3BDbHVzdGVyKGNsKQojIDAuMTQ0MDIxIC00My4xMDQ2IDIwMzAuMjcgLTUyNC42ODYgCiMgOC42OTU4OQpgYGAKCiMgaW1wb3J0IGFuZCBwcm9jZXNzIGRhdGEKYGBge3J9CiMgaW1wb3J0IGluIGRhdGEKc2lfcGFydGl0aW9uLmxzIDwtIGxpc3QuZmlsZXMocGF0aCA9IGhlcmUoImRhdGEvcGFydGl0aW9uL3NpLyIpLCBwYXR0ZXJuID0gIiouY3N2IiwgZnVsbC5uYW1lcyA9IFQpCnNpX3BhcnRpdGlvbi5scyA8LSBsYXBwbHkoc2lfcGFydGl0aW9uLmxzLCByZWFkLmNzdikKc2lfcGFydGl0aW9uLmRmIDwtIGRvLmNhbGwocmJpbmQsIHNpX3BhcnRpdGlvbi5scykKCiMgY29tYmluZSB3aXRoIHNpIGZpdG5lc3MgKGRlZmF1bHQpCnNpX3BhcnRpdGlvbi5kZiA8LSBzaV9wYXJ0aXRpb24uZGYgJT4lIGxlZnRfam9pbihzZWxlY3Qoc2lfZml0bmVzcy5kZiwgaWQsIGZpdG5lc3MgPSB2YWx1ZSksIGJ5ID0gImlkIikKCiMgbWFrZSBsb25nZXIKc2lfcGFydGl0aW9uLmRmMiA8LSB0aWR5cjo6cGl2b3RfbG9uZ2VyKHNpX3BhcnRpdGlvbi5kZiwgYyhmaXRuZXNzX1IsIGZpdG5lc3NfTiwgZml0bmVzc19XLCBmaXRuZXNzKSkKCiMgY2FsY3VsYXRlIGNvZWZmaWNpZW50IG9mIHZhcmlhdGlvbi4gQWxzbyByZW5hbWUKc2lfcGFydGl0aW9uLmRmMiA8LSBzaV9wYXJ0aXRpb24uZGYyICU+JSAKICBncm91cF9ieShuYW1lKSAlPiUgCiAgbXV0YXRlKGN2ID0gc2QodmFsdWUpL21lYW4odmFsdWUpKjEwMCwKICAgICAgICAgbWVhbiA9IG1lYW4odmFsdWUpLAogICAgICAgICBjYXRlZ29yeSA9IGNhc2Vfd2hlbigKICAgICAgICAgICBuYW1lID09ICJmaXRuZXNzX1IiIH4gIk5vIFJCQyBsaW1pdGF0aW9uIiwKICAgICAgICAgICBuYW1lID09ICJmaXRuZXNzX1ciIH4gIk5vIHRhcmdldGVkIGltbXVuaXR5IiwKICAgICAgICAgICBuYW1lID09ICJmaXRuZXNzX04iIH4gIk5vIGluZGlzY3JpbWluYXRlXG5pbW11bml0eSIsCiAgICAgICAgICAgbmFtZSA9PSAiZml0bmVzcyIgfiAiRGVmYXVsdCIKICAgICAgICAgKSkKCmBgYAoKIyBwbG90CmBgYHtyfQpsaWJyYXJ5KHVuZ2V2aXopCiMgcmF3IGZpdG5lc3MKc2lfcGFydGl0aW9uLnBsMSA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV92cGxpbmUoZGF0YSA9IHNpX3BhcnRpdGlvbi5kZjIsIGFlcyh5ID0gZmN0X3Jlb3JkZXIoY2F0ZWdvcnksIG1lYW4pLCB4ID0gbWVhbiwgZ3JvdXAgPSBjYXRlZ29yeSwgY29sb3IgPSBjYXRlZ29yeSksIHNob3cubGVnZW5kID0gRiwgc2l6ZSA9IDEpICsKICBnZW9tX3BvaW50KGRhdGEgPSBzaV9wYXJ0aXRpb24uZGYyLCBhZXMoeSA9IGZjdF9yZW9yZGVyKGNhdGVnb3J5LCBtZWFuKSwgeCA9IHZhbHVlKSwgc2l6ZSA9IDIsIGFscGhhID0gMC43KSArCiAgZ2VvbV9saW5lKGRhdGEgPSBzaV9wYXJ0aXRpb24uZGYyLCBhZXMoeSA9IGZjdF9yZW9yZGVyKGNhdGVnb3J5LCBtZWFuKSwgeCA9IHZhbHVlLCBncm91cCA9IGlkKSwgYWxwaGEgPSAwLjIpICsKICBsYWJzKHggPSAiRml0bmVzcyIsIHkgPSAiQ29uZGl0aW9ucyIpICsKICB0aGVtZV9idygpCgojIGNvZWZmaWNpZW50IG9mIHZhcmlhdGlvbgpzaV9wYXJ0aXRpb24ucGwyIDwtIGdncGxvdCgpICsKICBnZW9tX2JhcihkYXRhID0gc2lfcGFydGl0aW9uLmRmMiwgYWVzKHkgPSBmY3RfcmVvcmRlcihjYXRlZ29yeSwgbWVhbiksIHggPSBjdiksIHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgbGFicyh4ID0gIkNvZWZmaWNpZW50IG9mXG52YXJpYXRpb24gKCUpIiwgeSA9ICIiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50aXRsZS55PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55PWVsZW1lbnRfYmxhbmsoKSkKCnNpX3BhcnRpdGlvbi5wbCA8LSBnZ2FycmFuZ2Uoc2lfcGFydGl0aW9uLnBsMSwgc2lfcGFydGl0aW9uLnBsMiwgd2lkdGhzID0gYygxLCAwLjMpLCBhbGlnbiA9ICJoIikKc2lfcGFydGl0aW9uLnBsCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby9wYXJ0aXRpb25fZml0bmVzcy50aWZmIiksIHdpZHRoID0gNywgaGVpZ2h0ID0gNCkKYGBgCgojLS0tLS0tLSBjb25zZXF1ZW5jZXMgb2Ygbm8gdGFyZ2V0ZWQgaW1tdW5pdHkgLS0tLS0tLS0tLS0tIwojIGdldCBkeW5hbWljcyBvZiBubyB0YXJnZXRlZCBpbW11bml0eQpgYGB7cn0KZ2V0X2R5biA8LSBmdW5jdGlvbihkZil7CiAgCiAgc291cmNlKGhlcmUoImZ1bmN0aW9ucy9jaGFiYXVkaV9zaV9jbGVhbl9XLlIiKSkKICBpZCA8LSBkZiRpZAogIGN1ZSA8LSBkZiRjdWUKICBsb2cgPC0gZGYkbG9nCiAgcGFyIDwtIGMoZGYkdmFyX1cxLCBkZiR2YXJfVzIsIGRmJHZhcl9XMywgZGYkdmFyX1c0KQogIGN1ZV9yYW5nZSA8LSBzZXEoZGYkbG93LCBkZiRoaWdoLCBieSA9IGRmJGJ5KQogIAogICMgZ2V0IGR5bmFtaWNzCiAgZHluIDwtIGNoYWJhdWRpX3NpX2NsZWFuX1coCiAgICBwYXJhbWV0ZXJzX2NyID0gcGFyLAogICAgaW1tdW5pdHkgPSAidHN1a3VzaGkiLAogICAgcGFyYW1ldGVycyA9IHBhcmFtZXRlcnNfdHN1a3VzaGksCiAgICB0aW1lX3JhbmdlID0gc2VxKDAsIDIwLCBieSA9IDFlLTMpLAogICAgY3VlX3JhbmdlID0gIGN1ZV9yYW5nZSwKICAgIGN1ZSA9IGN1ZSwKICAgIGxvZ19jdWUgPSBsb2csCiAgICBzb2x2ZXIgPSAidm9kZSIsCiAgICBkeW4gPSBUCiAgKQogIAogICMgY29tYmluZQogIGR5bjIgPC0gY2JpbmQoZHluLCBpZCA9IGlkLCBjdWUgPSBjdWUsIGxvZyA9IGxvZykKICAKICB3cml0ZV9wYXJxdWV0KGR5bjIsIHBhc3RlMChoZXJlKCJkYXRhL3BhcnRpdGlvbi9zaV9keW4vIiksIGlkLCAiX25vV19keW4ucGFycXVldCIpKQogIAp9CmBgYAoKIyBnZXQgZGYgdG8gcnVuCmBgYHtyfQojIGpvaW4gd2l0aCBjdWVfcmFuZ2UKY3VlX3JhbmdlX3NpLmRmIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvY3VlX3JhbmdlX3NpLmNzdiIpKQpzaV9wYXJ0aXRpb24uZGYzIDwtIHNpX3BhcnRpdGlvbi5kZiAlPiUgbGVmdF9qb2luKHNlbGVjdChjdWVfcmFuZ2Vfc2kuZGYsIGxvdywgaGlnaCwgYnksIGlkKSwgImlkIikKCiMgbGFwcGx5IGxvb3AKc2lfcGFydGl0aW9uLmxzIDwtIHNwbGl0KHNpX3BhcnRpdGlvbi5kZjMsIHNlcShucm93KHNpX3BhcnRpdGlvbi5kZjMpKSkKbWNsYXBwbHkoc2lfcGFydGl0aW9uLmxzLCBnZXRfZHluKQpgYGAKCiMgcHJvY2VzcyBkYXRhZnJhbWUKYGBge3J9CiMgaW1wb3J0IGluIGRhdGFmcmFtZQpub19XLmxzIDwtIGxpc3QuZmlsZXMoaGVyZSgiZGF0YS9wYXJ0aXRpb24vc2lfZHluLyIpLCBwYXR0ZXJuID0gIipub1dfZHluLnBhcnF1ZXQiLCBmdWxsLm5hbWVzID0gVCkKbm9fVy5kZiA8LSBsYXBwbHkobm9fVy5scywgcmVhZF9wYXJxdWV0KQpub19XLmRmIDwtIGRvLmNhbGwocmJpbmQsIG5vX1cuZGYpCgojIGNvbWJpbmUgd2l0aCBleiBsYWJlbAplel9sYWJlbCA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2V6X2xhYmVsLmNzdiIpKQpub19XLmRmIDwtIGxlZnRfam9pbihub19XLmRmLCBlel9sYWJlbCwgYnkgPSBjKCJpZCIgPSAiaWRfc2kiKSkKCiMgZ2V0IGNvbnZlcnNpb24gcmF0ZSAKbm9fVy5jciA8LSBub19XLmRmICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gImNyIikKbm9fVy5JIDwtIG5vX1cuZGYgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiSSIpCgojIGdldCBkZWZhdWx0IGNvbnZlcnNpb24gcmF0ZSBkeW5hbWljcwpzaV9keW4uZGYgPC0gbGVmdF9qb2luKHNpX2R5bi5kZiwgZXpfbGFiZWwsIGJ5ID0gYygiaWQiID0gImlkX3NpIikpCnNpX2R5bi5jciA8LSBzaV9keW4uZGYgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiY3IiKQpzaV9keW4uSSA8LSBzaV9keW4uZGYgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiSSIpCmBgYAoKIyBwbG90IGNvbnZlcnNpb24gcmF0ZQptZWNoYW5pc206IHRhcmdldGVkIGltbXVuaXR5IGxlZCB0byBsb3dlciBwYXJhc2l0ZSBkZW5zaXR5IGluIHRoZSBpbml0aWFsIHN0YWdlcywgd2hpY2ggcHJldmVudHMgcGFyYXNpdGVzIGZyb20gbWFraW5nIHRoZSBzd2l0Y2ggZnJvbSBubyBjb252ZXJzaW9uIHJhdGUgdG8gaGlnaCBjb252ZXJzaW9uIHJhdGUuIFdoZW4gcGFyc2l0ZSBkZW5zaXR5IHVuZGVyZ29lcyBkcmFzdGljIGluY3JlYXNlIGF0IHRoZSBiZWdpbm5pbmcgZHVlIHRvIGxvd2VyIGltbXVuaXR5LCB0aGlzIHByZXNlbnRzIGEgaGlnaGVyIGRlZ3JlZSBvZiBzaWduYWwgdGhhdCBhbGxvd3MgcGFyYXNpdGUgdG8gbWFrZSB0aGUgc3dpdGNoIGFwcHJvcHJpYXRlbHkKYGBge3J9CnBhcnRpdGlvbl9jci5wbCA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBub19XLmNyLCBhZXMoeCA9IHRpbWUsIHk9IHZhbHVlLCBjb2xvciA9ICJObyB0YXJnZXRlZCBpbW11bml0eSIpKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBzaV9keW4uY3IsIGFlcyh4ID0gdGltZSwgeT0gdmFsdWUsIGNvbG9yID0gIkRlZmF1bHQiKSkgKwogIGZhY2V0X3dyYXAofmV6X2xhYmVsX3NpLCBuY29sID0gNSkgKwogIHhsaW0oMCwgMjApICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSA3KSArCiAgbGFicyh4ID0gIlRpbWUgKGRheXMpIiwgeSA9ICJDb252ZXJzaW9uIHJhdGUiLCBjb2xvciA9ICJDb25kaXRpb24iKSArCiAgdGhlbWVfYncoKQoKbm9fVy5jcgpgYGAKCiMtLS0tLSBjdWUgc3RhdGUgLS0tLS0tLS0tLS0tLS0jCgojIGZ1bmN0aW9uIHRvIGdldCBjdWUgc3RhdGVzCmBgYHtyfQojIGZ1bmN0aW9uIHRvIGdldCBjdWUgc3RhdGVzCmdldF9jdWVfc3RhdGUgPC0gZnVuY3Rpb24oZGYpewogIGN1ZSA8LSB0cmltd3MoZ3N1YigiX2xvZ3xfbm9uZSIsICIiLCB1bmlxdWUoZGYkaWQpKSkKICBpZihjdWUgIT0gIkkrSWciKXsKICBkZjIgPC0gZGYgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSBjdWUpCiAgaWYoc3RyX2RldGVjdCh1bmlxdWUoZGYkaWQpLCAibG9nIikpewogICAgZGYyIDwtIGRmMiAlPiUgCiAgICAgIG11dGF0ZSh2YWx1ZSA9IGxvZzEwKHZhbHVlKSkKICB9CiAgfQogIAogIGlmKGN1ZSA9PSAiSStJZyIpewogICAgZGYyIDwtIGRmICU+JSBmaWx0ZXIodmFyaWFibGUgJWluJSBjKCJJIiwgIklnIikpICU+JSAKICAgICAgZ3JvdXBfYnkodGltZSkgJT4lIAogICAgICBtdXRhdGUodmFsdWUgPSBzdW0odmFsdWUpKQogICAgCiAgICBpZihzdHJfZGV0ZWN0KHVuaXF1ZShkZiRpZCksICJsb2ciKSl7CiAgICBkZjIgPC0gZGYyICU+JSAKICAgICAgbXV0YXRlKHZhbHVlID0gbG9nMTAodmFsdWUpKQogIH0KICB9CiAgCiAgZGYyJHZhbHVlW2RmMiR2YWx1ZSA9PSAtSW5mXSA8LSAwCiAgCiAgd3JpdGVfcGFycXVldChkZjIsIHBhc3RlMChoZXJlKCJkYXRhL3BhcnRpdGlvbi9zaV9kZWZhdWx0X3N0YXRlLyIpLCB1bmlxdWUoZGYkaWQpLCAiX25vV19zdGF0ZS5wYXJxdWV0IikpCn0KYGBgCgojIHJ1biBmdW5jdGlvbgpgYGB7cn0KIyBzcGxpdCBkeW5hbWljcyBiYXNlZCBvbiBpZApub19XLnNwbGl0IDwtIHNwbGl0KG5vX1cuZGYsIG5vX1cuZGYkaWQpCgojIHJ1biBmdW5jdGlvbgptY2xhcHBseShub19XLnNwbGl0LCBnZXRfY3VlX3N0YXRlKQoKIyBnZXQgZGF0YWZyYW1lCm5vX1cuc3RhdGUgPC0gbGlzdC5maWxlcyhoZXJlKCJkYXRhL3BhcnRpdGlvbi9zaV9zdGF0ZS8iKSwgcGF0dGVybiA9ICIqLnBhcnF1ZXQiLCBmdWxsLm5hbWVzID0gVCkKbm9fVy5zdGF0ZSA8LSBsYXBwbHkobm9fVy5zdGF0ZSwgcmVhZF9wYXJxdWV0KQpub19XLnN0YXRlIDwtIGRvLmNhbGwocmJpbmQsIG5vX1cuc3RhdGUpCm5vX1cuc3RhdGUkdmFsdWVbbm9fVy5zdGF0ZSR2YWx1ZSA8IDBdIDwtIDAKCiMgZ2V0IHNhbWUgZm9yIHNpIGluZmVjdGlvbgpkZWZhdWx0LnNwbGl0IDwtIHNwbGl0KHNpX2R5bi5kZiwgc2lfZHluLmRmJGlkKQptY2xhcHBseShkZWZhdWx0LnNwbGl0LCBnZXRfY3VlX3N0YXRlKQpkZWZhdWx0LnN0YXRlIDwtIGxpc3QuZmlsZXMoaGVyZSgiZGF0YS9wYXJ0aXRpb24vc2lfZGVmYXVsdF9zdGF0ZS8iKSwgcGF0dGVybiA9ICIqLnBhcnF1ZXQiLCBmdWxsLm5hbWVzID0gVCkKZGVmYXVsdC5zdGF0ZSA8LSBsYXBwbHkoZGVmYXVsdC5zdGF0ZSwgcmVhZF9wYXJxdWV0KQpkZWZhdWx0LnN0YXRlIDwtIGRvLmNhbGwocmJpbmQsIGRlZmF1bHQuc3RhdGUpCmRlZmF1bHQuc3RhdGUkdmFsdWVbZGVmYXVsdC5zdGF0ZSR2YWx1ZSA8IDBdIDwtIDAKCiMgbWFudWFsbHkgY29ycmVjdCBub24tbG9nZ2luZwpJX0lnLmNvcnIgPC0gbm9fVy5zdGF0ZSAlPiUgZmlsdGVyKGlkID09ICJJK0lnX2xvZyIpICU+JSAKICBtdXRhdGUodmFsdWUgPSBsb2cxMCh2YWx1ZSkpCklfSWcuY29yciR2YWx1ZVtJX0lnLmNvcnIkdmFsdWUgPCAwXSA8LSAwCgpub19XLnN0YXRlMiA8LSBub19XLnN0YXRlICU+JSBmaWx0ZXIoaWQgIT0gIkkrSWdfbG9nIikKbm9fVy5zdGF0ZTIgPC0gbm9fVy5zdGF0ZTIgJT4lIHJiaW5kKG5vX1cuc3RhdGUyLCBJX0lnLmNvcnIpCmBgYAoKIyBwbG90CmFic2VuY2Ugb2YgdGFyZ2V0ZWQgaW1tdW5pdHkgbGVkIHRvIGRyYXN0aWMgaW5jcmVhc2UgaW4gcGFyYXNpdGUgZGVuc2l0eSBpbiBlYXJseSBwaGFzZXMgb2YgaW5mZWN0aW9uLiBUaGlzIHByb2R1Y2VzIGhpZ2ggc2lnbmFsIGludGVuc2l0eSBmb3IgcGFyYXNpdGUgYW5kIGhvc3QtYmFzZWQgY3VlcywgZXNwZWNpYWxseSBub24tbG9nZ2VkIG9uZXMsIHdoaWNoIGFsbG93cyBmb3Igc3RhdGUgZGlmZmVyZW50YXRpb24uIFdoaWxlIHRoaXMgY2FuIGJlIHZpZXdlZCBhcyBhIG1vZGVsbGluZyBhcnRpZmlhY3QsIGl0IHNob3VsZCBiZSBub3RlZCB0aGF0IHRoZSBsb2dnZWQgY3VlcyBzZWxkb20gY2hhbmdlZCBhcyB0aGVzZSBjaGFuZ2VzIGluIGVhcmx5IGluZmVjdGlvbiBkaWQgbGl0dGxlIHRvIGFsdGVyIHRoZSBhY3R1YWwgZWFybHkgc2lnbmFsIGludGVuc2l0eSBzZW5zZWQgYnkgdGhlIHBhcmFzaXRlLiBJbiBhbiBlbnZpcm9ubWVudCB3aGVyZSB0aGVyZSBpcyBoZXRlcm9nZW5laXR5IGluIGhvc3QgcmVzcG9uc2UsIGFuZCB0aHVzLCBzaWduYWwsIGxvZ2dpbmcgYWxsb3dzIGZvciBwYXJhc2l0ZXMgdG8gYWRhcHQgb3B0aW1hbCBzdHJhdGVneSB3aGVyZWFzIG5vbi1sb2dnZWQgY3VlcyBtdXN0IGNvbnRlbmQgd2l0aCBzZW5zaXRpdml0eSB0byBpbW11bml0eS4KYGBge3J9CiMgZnVuY3Rpb24gdG8gaW5kaXZpZHVhbGx5IHBsb3Qgc3R1ZmYKcGxvdF9zdGF0ZSA8LSBmdW5jdGlvbihkZjEsIGRmMil7CiAgCiAgIyBwbG90IHN0YXRlIGR5bmFtaWNzCiAgc3RhdGVfcGwgPC0gZ2dwbG90KCkgKwogIGdlb21fbGluZShkYXRhID0gZGYxLCBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZSwgY29sb3IgPSBuYW1lLCBncm91cCA9IG5hbWUpKSArCiAgZmFjZXRfd3JhcCh+ZXpfbGFiZWxfc2ksIHNjYWxlcyA9ICJmcmVlIikgKwogIHhsaW0oMSwyMCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsKICBsYWJzKHggPSAiIiwgeSA9ICJDdWUiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID1jKCJEZWZhdWx0IiA9ICIjNDU3NWI0IiwgIk5vIHRhcmdldGVkXG5pbW11bml0eSIgPSAiI2ZjOGQ1OSIpKQogIAogICMgcGxvdCBjb252ZXJzaW9uIHJhdGUgZHluYW1pY3MKICBjcl9wbCA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9yYXN0ZXIoZGF0YSA9IGRmMiwgYWVzKHggPSB0aW1lLCB5ID0gbmFtZSwgZmlsbCA9IHZhbHVlKSkgKwogIHhsaW0oMSwyMCkgKwogIHRoZW1lX2J3KCkgKwogICAgbGFicyh4ID0gIlRpbWUgKGRheXMpIikgKwogIHRoZW1lKGF4aXMudGl0bGUueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICAgIHNjYWxlX2ZpbGxfdmlyaWRpc19jKGxpbSA9IGMoMCwgMSkpCiAgCiAgIyBhcnJhbmdlCiAgZ2dhcnJhbmdlKHN0YXRlX3BsLCBjcl9wbCwgbmNvbCA9IDEsIG5yb3cgPSAyLCBhbGlnbiA9ICJ2IiwgaGVpZ2h0cyA9IGMoMSwgMC40KSkKICBnZ3NhdmUocGFzdGUwKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vcGFydGl0aW9uLyIpLCB1bmlxdWUoZGYxJGlkKSwgIi50aWZmIiksIHdpZHRoID0gNC41LCBoZWlnaHQgPSAzLjUpCn0KYGBgCgojIHNwbGl0CmBgYHtyfQojIGNvbWJpbmUgc3RhdGUKbm9XX2RlZmF1bHQuc3RhdGUgPC0gbGVmdF9qb2luKAogIHNlbGVjdChub19XLnN0YXRlMiwgdGltZSwgYE5vIHRhcmdldGVkXG5pbW11bml0eWAgPSB2YWx1ZSwgaWQsIGV6X2xhYmVsX3NpKSwgCiAgc2VsZWN0KGRlZmF1bHQuc3RhdGUgJT4lIGZpbHRlcih0aW1lIDw9IDIwKSwgdGltZSwgYERlZmF1bHRgID0gdmFsdWUsIGlkLCBlel9sYWJlbF9zaSksIGJ5ID0gYygidGltZSIsICJpZCIsICJlel9sYWJlbF9zaSIpKQoKbm9XX2RlZmF1bHQuc3RhdGUyIDwtIHRpZHlyOjpwaXZvdF9sb25nZXIobm9XX2RlZmF1bHQuc3RhdGUsIGMoYE5vIHRhcmdldGVkXG5pbW11bml0eWAsIGBEZWZhdWx0YCkpCiMgY29tYmluZSBjb252ZXJzaW9uIHJhc3Rlcgpub1dfZGVmYXVsdC5jciA8LSBsZWZ0X2pvaW4oCiAgc2VsZWN0KG5vX1cuY3IsIHRpbWUsIGBObyB0YXJnZXRlZFxuaW1tdW5pdHlgID0gdmFsdWUsIGlkLCBlel9sYWJlbF9zaSksIAogIHNlbGVjdChzaV9keW4uY3IgJT4lIGZpbHRlcih0aW1lIDw9IDIwKSwgdGltZSwgYERlZmF1bHRgID0gdmFsdWUsIGlkLCBlel9sYWJlbF9zaSksIGJ5ID0gYygidGltZSIsICJpZCIsICJlel9sYWJlbF9zaSIpKQpub1dfZGVmYXVsdC5jcjIgPC0gdGlkeXI6OnBpdm90X2xvbmdlcihub1dfZGVmYXVsdC5jciwgYyhgTm8gdGFyZ2V0ZWRcbmltbXVuaXR5YCwgYERlZmF1bHRgKSkKCiMgc3BsaXQKbm9XX2RlZmF1bHRfc3RhdGUubHMgPC0gc3BsaXQobm9XX2RlZmF1bHQuc3RhdGUyLCBub1dfZGVmYXVsdC5zdGF0ZTIkaWQpCm5vV19kZWZhdWx0X2NyLmxzIDwtIHNwbGl0KG5vV19kZWZhdWx0LmNyMiwgbm9XX2RlZmF1bHQuY3IyJGlkKQoKIyBydW4gZnVuY3Rpb24KbWFwcGx5KHBsb3Rfc3RhdGUsIG5vV19kZWZhdWx0X3N0YXRlLmxzLCBub1dfZGVmYXVsdF9jci5scykKYGBgCgojLS0tLS0tLS0gcmVhY3Rpb24gbm9ybXMgb2YgZGVmYXVsdCB2cyBvcHRpbWl6ZWQgLS0tLS0tLS0tLS0tIwojIGdldCByZWFjdGlvbiBub3JtIGFuZCBydWcgZGF0YQpgYGB7cn0Kc291cmNlKGhlcmUoImZ1bmN0aW9ucy9wYXJfdG9fZGYuUiIpKQoKIyBHYW1ldG9jeXRlCmdfbG9nLnJuIDwtIHBhcl90b19kZihwYXIgPSBjKDEuMjExNTIxLAktMy45MzY3NzgsCS0xLjMxMjk0NCwJLTEuMjg1NzEzKSwgY3VlX3JhbmdlID0gc2VxKDAsIGxvZzEwKDYqKDEwXjQpKSwgYnkgPSAobG9nMTAoNiooMTBeNCkpKS81MDAwKSkKZ19sb2cucm4yIDwtIHBhcl90b19kZihwYXIgPSBjKDEuMzkzODYwNTM5LAktNC4yNTMwMDc2MTYsCS0wLjMxMzk0NzAyOSwJLTIuMDAwODU3MzQ0KSwgY3VlX3JhbmdlID0gc2VxKDAsIGxvZzEwKDYqKDEwXjQpKSwgYnkgPSAobG9nMTAoNiooMTBeNCkpKS81MDAwKSkKCmcucm4gPC0gcGFyX3RvX2RmKHBhciA9IGMoMC4wNDA2MTI4OCwJLTkuMzE0NDU5NTgsCTc0LjEzMDE1NTA2LAktNDMxLjU5ODQzNjQpLCBjdWVfcmFuZ2UgPSBzZXEoMCwgNiooMTBeNCksIGJ5ID0gKDYqKDEwXjQpKS81MDAwKSkKZy5ybjIgPC0gcGFyX3RvX2RmKHBhciA9IGMoMC41NDE3MjkwNzMsCS0zLjkwNDYxNjQ0MywJMC44NzQ4NzQxMiwJLTAuNjk0MTc3MDIxKSwgY3VlX3JhbmdlID0gc2VxKDAsIDYqKDEwXjQpLCBieSA9ICg2KigxMF40KSkvNTAwMCkpCgojIEkrSWcKSV9JZ19sb2cucm4gPC0gcGFyX3RvX2RmKHBhciA9IGMoMy41OTQwNDIsCTQuMTU3NzQ0LAktMTMuNTMwNjcyLAkyLjU5OTkwNSksIGN1ZV9yYW5nZSA9IHNlcSgwLCBsb2cxMCg2KigxMF42KSksIGJ5ID0gKGxvZzEwKDYqKDEwXjYpKSkvNTAwMCkpCklfSWdfbG9nLnJuMiA8LSBwYXJfdG9fZGYocGFyID0gYyg2My43MTg5MzgyMiwJLTg3Ljc3NjcxNjAxLAktNTYuNTU0NzU1MTQsCS02Ni4wMjIwOTU0OSksIGN1ZV9yYW5nZSA9IHNlcSgwLCBsb2cxMCg2KigxMF42KSksIGJ5ID0gKGxvZzEwKDYqKDEwXjYpKSkvNTAwMCkpCgpJX0lnLnJuIDwtIHBhcl90b19kZihwYXIgPSBjKDAuMzE1OTI5NywJLTQ2LjExMDQ1NTgsCTEyNTAuNzUyOTA4LAktNi4xOTgyMDkzKSwgY3VlX3JhbmdlID0gc2VxKDAsIDYqKDEwXjYpLCBieSA9ICg2KigxMF42KSkvNTAwMCkpCklfSWcucm4yIDwtIHBhcl90b19kZihwYXIgPSBjKDAuNzMxOTgyNzg0LAktMjEuNjk3OTk0NDksCTE0OS43ODQxODc2LAkxNy4wMjU1MTc2OSksIGN1ZV9yYW5nZSA9IHNlcSgwLCA2KigxMF42KSwgYnkgPSAoNiooMTBeNikpLzUwMDApKQoKIyBjb252ZXJ0IGxvZyB0byBub24tbG9nZ2VkIHNjYWxlCmdfbG9nLnJuJGN1ZV9yYW5nZSA8LSAxMF4oZ19sb2cucm4kY3VlX3JhbmdlKQpnX2xvZy5ybjIkY3VlX3JhbmdlIDwtIDEwXihnX2xvZy5ybjIkY3VlX3JhbmdlKQpJX0lnX2xvZy5ybiRjdWVfcmFuZ2UgPC0gMTBeKElfSWdfbG9nLnJuJGN1ZV9yYW5nZSkKSV9JZ19sb2cucm4yJGN1ZV9yYW5nZSA8LSAxMF4oSV9JZ19sb2cucm4yJGN1ZV9yYW5nZSkKCiMgZ2V0IHJ1ZwpnX2xvZy5ydWcgPC0gZGVmYXVsdC5zdGF0ZSAlPiUgCiAgZmlsdGVyKGxhYmVsX3NpID09ICJHIGxvZyIpICU+JSAKICBtdXRhdGUodmFsdWUgPSAxMF52YWx1ZSkgJT4lIAogIHNlbGVjdChsYWJlbF9zaSwgdmFsdWUpCgpnX2xvZy5ydWcyIDwtIG5vX1cuc3RhdGUgJT4lIAogIGZpbHRlcihsYWJlbF9zaSA9PSAiRyBsb2ciKSAlPiUgCiAgbXV0YXRlKHZhbHVlID0gMTBedmFsdWUpICU+JSAKICBmaWx0ZXIodmFsdWUgPD0gNiooMTBeNCkpICU+JSAKICBzZWxlY3QobGFiZWxfc2ksIHZhbHVlKQoKSV9JZ19sb2cucnVnIDwtIGRlZmF1bHQuc3RhdGUgJT4lIAogIGZpbHRlcihsYWJlbF9zaSA9PSAiSStJZyBsb2ciKSAlPiUgCiAgc2VsZWN0KGxhYmVsX3NpLCB2YWx1ZSkKCklfSWdfbG9nLnJ1ZzIgPC0gbm9fVy5zdGF0ZSAlPiUgCiAgZmlsdGVyKGxhYmVsX3NpID09ICJJK0lnIGxvZyIpICU+JSAKICBzZWxlY3QobGFiZWxfc2ksIHZhbHVlKQoKZy5ydWcgPC0gZGVmYXVsdC5zdGF0ZSAlPiUgCiAgZmlsdGVyKGxhYmVsX3NpID09ICJHIikgJT4lIAogIHNlbGVjdChsYWJlbF9zaSwgdmFsdWUpCgpnLnJ1ZzIgPC0gbm9fVy5zdGF0ZSAlPiUgCiAgZmlsdGVyKGxhYmVsX3NpID09ICJHIiAmIHZhbHVlIDw9IDYqKDEwXjQpKSAlPiUgCiAgc2VsZWN0KGxhYmVsX3NpLCB2YWx1ZSkKCklfSWcucnVnIDwtIGRlZmF1bHQuc3RhdGUgJT4lIAogIGZpbHRlcihsYWJlbF9zaSA9PSAiSStJZyIpICU+JSAKICBzZWxlY3QobGFiZWxfc2ksIHZhbHVlKQoKSV9JZy5ydWcyIDwtIG5vX1cuc3RhdGUgJT4lIAogIGZpbHRlcihsYWJlbF9zaSA9PSAiSStJZyIpICU+JSAKICBzZWxlY3QobGFiZWxfc2ksIHZhbHVlKQoKIyBnZXQgcnVnIGxpbWl0cwpydWdfbGltIDwtIHJiaW5kKGdfbG9nLnJ1ZywKICAgICAgICAgICAgICAgICBnX2xvZy5ydWcyLAogICAgICAgICAgICAgICAgIElfSWdfbG9nLnJ1ZywKICAgICAgICAgICAgICAgICBJX0lnX2xvZy5ydWcyLAogICAgICAgICAgICAgICAgIGcucnVnLAogICAgICAgICAgICAgICAgIGcucnVnMiwKICAgICAgICAgICAgICAgICBJX0lnLnJ1ZywKICAgICAgICAgICAgICAgICBJX0lnLnJ1ZzIpICU+JSAKICBncm91cF9ieShsYWJlbF9zaSkgJT4lIAogIHN1bW1hcml6ZShtYXggPSBtYXgoaGFibGFyOjpzKHZhbHVlKSwgbmEucm0gPSBUKSwKICAgICAgICAgICAgbWluID0gbWluKGhhYmxhcjo6cyh2YWx1ZSksIG5hLnJtID0gVCkpCgojIGNvbWJpbmUgYW5kIGZpbHRlcgpybiA8LSByYmluZCgKICBjYmluZChnX2xvZy5ybiwgbGFiZWxfc2kgPSAiRyBsb2ciLCBjb25kaXRpb24gPSAiRGVmYXVsdCIpLAogIGNiaW5kKGdfbG9nLnJuMiwgbGFiZWxfc2kgPSAiRyBsb2ciLCBjb25kaXRpb24gPSAiTm8gdGFyZ2V0ZWRcbmltbXVuaXR5IiksCiAgY2JpbmQoZy5ybiwgbGFiZWxfc2kgPSAiRyIsIGNvbmRpdGlvbiA9ICJEZWZhdWx0IiksCiAgY2JpbmQoZy5ybjIsIGxhYmVsX3NpID0gIkciLCBjb25kaXRpb24gPSAiTm8gdGFyZ2V0ZWRcbmltbXVuaXR5IiksCiAgY2JpbmQoSV9JZ19sb2cucm4sIGxhYmVsX3NpID0gIkkrSWcgbG9nIiwgY29uZGl0aW9uID0gIkRlZmF1bHQiKSwKICBjYmluZChJX0lnX2xvZy5ybjIsIGxhYmVsX3NpID0gIkkrSWcgbG9nIiwgY29uZGl0aW9uID0gIk5vIHRhcmdldGVkXG5pbW11bml0eSIpLAogIGNiaW5kKElfSWcucm4sIGxhYmVsX3NpID0gIkkrSWciLCBjb25kaXRpb24gPSAiRGVmYXVsdCIpLAogIGNiaW5kKElfSWcucm4yLCBsYWJlbF9zaSA9ICJJK0lnIiwgY29uZGl0aW9uID0gIk5vIHRhcmdldGVkXG5pbW11bml0eSIpCikgJT4lIAogIGxlZnRfam9pbihydWdfbGltLCBieSA9ICJsYWJlbF9zaSIpICU+JSAKICBncm91cF9ieShsYWJlbF9zaSkgJT4lIAogIGZpbHRlcihjdWVfcmFuZ2UgPD0gbWF4ICYgY3VlX3JhbmdlID49IG1pbikKCiMgY29tYmluZSBydWcKcnVnIDwtIHJiaW5kKGNiaW5kKGdfbG9nLnJ1ZywgY29uZGl0aW9uID0gIkRlZmF1bHQiKSwKICAgICAgICAgICAgIGNiaW5kKGdfbG9nLnJ1ZzIsIGNvbmRpdGlvbiA9ICJObyB0YXJnZXRlZFxuaW1tdW5pdHkiKSwKICAgICAgICAgICAgIGNiaW5kKGcucnVnLCBjb25kaXRpb24gPSAiRGVmYXVsdCIpLAogICAgICAgICAgICAgY2JpbmQoZy5ydWcyLCBjb25kaXRpb24gPSAiTm8gdGFyZ2V0ZWRcbmltbXVuaXR5IiksCiAgICAgICAgICAgICBjYmluZChJX0lnX2xvZy5ydWcsIGNvbmRpdGlvbiA9ICJEZWZhdWx0IiksCiAgICAgICAgICAgICBjYmluZChJX0lnX2xvZy5ydWcyLCBjb25kaXRpb24gPSAiTm8gdGFyZ2V0ZWRcbmltbXVuaXR5IiksCiAgICAgICAgICAgICBjYmluZChJX0lnLnJ1ZywgY29uZGl0aW9uID0gIkRlZmF1bHQiKSwKICAgICAgICAgICAgIGNiaW5kKElfSWcucnVnMiwgY29uZGl0aW9uID0gIk5vIHRhcmdldGVkXG5pbW11bml0eSIpKQoKIyBjb2JpbmUgd2l0aCBlemxhYmVsCnJuMiA8LSBybiAlPiUgbGVmdF9qb2luKGV6X2xhYmVsLCBieSA9ICJsYWJlbF9zaSIpCnJ1ZzIgPC0gcnVnICU+JSBsZWZ0X2pvaW4oZXpfbGFiZWwsIGJ5ID0gImxhYmVsX3NpIikKCiMgZmlsdGVyIHJ1ZwpkZWZhdWx0LnJ1ZyA8LSBydWcyICU+JSBmaWx0ZXIoY29uZGl0aW9uID09ICJEZWZhdWx0IikKbm8ucnVnIDwtIHJ1ZzIgJT4lIGZpbHRlcihjb25kaXRpb24gPT0gIk5vIHRhcmdldGVkXG5pbW11bml0eSIpCmBgYAoKIyBwbG90CmBgYHtyfQpnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBybjIsIGFlcyh4ID0gY3VlX3JhbmdlLCB5ID0gY3IsIGNvbG9yID0gY29uZGl0aW9uKSkgKwogIGdlb21fcnVnKGRhdGEgPSBkZWZhdWx0LnJ1ZywgYWVzKHggPSB2YWx1ZSwgY29sb3IgPSBjb25kaXRpb24pLCBzaWRlcyA9ICJiIikgKwogIGdlb21fcnVnKGRhdGEgPSBuby5ydWcsIGFlcyh4ID0gdmFsdWUsIGNvbG9yID0gY29uZGl0aW9uKSwgc2lkZXMgPSAidCIpICsKICBmYWNldF93cmFwKH5mY3RfcmVsZXZlbChlel9sYWJlbF9zaSwgYygiR2FtZXRvY3l0ZSBsb2cxMCIsICJHYW1ldG9jeXRlIiwgIkFzZXh1YWwmc2V4dWFsXG5pUkJDIGxvZzEwIiwgIkFzZXh1YWwmc2V4dWFsIGlSQkMiKSksIHNjYWxlcyA9ICJmcmVlX3giKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gVFJVRSkpICsKICB0aGVtZV9idygpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID1jKCJEZWZhdWx0IiA9ICIjNDU3NWI0IiwgIk5vIHRhcmdldGVkXG5pbW11bml0eSIgPSAiI2ZjOGQ1OSIpKSArCiAgeWxpbSgwLCAxLjEpICsKICBsYWJzKHggPSAiQ3VlIHJhbmdlIiwgeSA9ICJDb252ZXJzaW9uIHJhdGUiLCBjb2xvciA9ICJDb25kaXRpb24iKQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vcGFydGl0aW9uX3JuLnRpZmYiKSwgd2lkdGggPSA3LjUsIGhlaWdodCA9IDYpCmBgYAoKIyBnZXQgY29udmVyc2lvbiByYXRlIGxlZ2VuZApgYGB7cn0Kbm9XX2RlZmF1bHQuY3IgJT4lIGZpbHRlcihpZCA9PSAiR19sb2ciKSAlPiUgCmdncGxvdCgpICsKICBnZW9tX3Jhc3RlcihhZXMoeCA9IHRpbWUsIHkgPSBpZCwgZmlsbCA9IERlZmF1bHQpKSArCiAgeGxpbSgxLDIwKSArCiAgdGhlbWVfYncoKSArCiAgICBsYWJzKHggPSAiVGltZSAoZGF5cykiLAogICAgICAgICBmaWxsID0gIkNvbnZlcnNpb24gcmF0ZSIpICsKICB0aGVtZShheGlzLnRpdGxlLnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCksKSArCiAgICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhsaW0gPSBjKDAsIDEpKQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vY3JfbGVnZW5kLnRpZmYiKSkKYGBgCgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMgRGlzZWFzZSBjdXJ2ZXMgZm9yIHNpbmdsZSwgY28taW5mZWN0aW9uLCBhbmQgaW52YXNpb24KIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMgZ2V0IGRhdGEgZm9yIGRpc2Vhc2UgY3VydmVzCmBgYHtyfQojIHNpbmdsZSBpbmZlY3Rpb24gZHluYW1pY3MKc2lfZHluLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL3NpX2R5bi9zaV9keW5fMzAucGFycXVldCIpKSAKCiMgY28taW5mZWN0aW9uIGR5bmFtaWNzIChtb24tY3VlKQpjaV9keW4uZGYgPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvY2lfZHluL2NpX2R5bi5wYXJxdWV0IikpCgojIGR1YWwgY3VlIGR5bmFtaWNzCmR1YWxfZHluLmRmIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2R1YWxfY3VlX2R5bi9kdWFsX2N1ZV9keW4ucGFycXVldCIpKQpgYGAKCiMtLS0tLS0tIHNpbmdsZSBjdWUgY29tcGFyaXNvbiAtLS0tLS0tLS0tLS0tLS0jCiMgcHJvY2VzcyBkYXRhCmBgYHtyfQojIGdldCBjbGFzc2lmaWNhdGlvbgpzaV9jdWUuZHYgPC0gc2lfZml0bmVzcy5kZiAlPiUgCiAgbXV0YXRlKGNsYXNzaWZpY2F0aW9uID0gY2FzZV93aGVuKAogICAgdmFsdWUgPiA5LjIgfiAiSGlnaC1wZXJmb3JtaW5nIiwKICAgIHZhbHVlIDw9IDkuMiB+ICJQb29yLXBlcmZvcm1pbmciCiAgKSkKCiMgcHJvY2VzcyBkeW5hbWljcyAtPiB0dXJuIHNraW5ueQpzaV9kYy5kZiA8LSBzaV9keW4uZGYgJT4lIAogIGZpbHRlcih2YXJpYWJsZSA9PSAiSSIgfCB2YXJpYWJsZSA9PSAiSWciIHwgdmFyaWFibGUgPT0gIlIiKSAlPiUgCiAgdGlkeXI6OnBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSB2YXJpYWJsZSwgdmFsdWVzX2Zyb20gPSB2YWx1ZSkgJT4lIAogIG11dGF0ZSh0b3RhbCA9IEkrSWcpCgojIGpvaW4gd2l0aCBjbGFzc2lmaWNhaXRvbgpzaV9kYy5kZjIgPC0gc2lfZGMuZGYgJT4lIGxlZnRfam9pbihzZWxlY3Qoc2lfY3VlLmR2LCBpZCwgY2xhc3NpZmljYXRpb24pLCBieSA9ICJpZCIpCnNpX2N1ZS5kdgojIHNwbGl0IGludG8gdG9wIGVyZm9ybWluZyBhbmQgcG9vci1wZXJmb3JtaW5nIGN1ZXMKc2lfZGMuaGlnaCA8LSBzaV9kYy5kZjIgJT4lIGZpbHRlcihjbGFzc2lmaWNhdGlvbiA9PSAiSGlnaC1wZXJmb3JtaW5nIikKc2lfZGMucG9vciA8LSBzaV9kYy5kZjIgJT4lIGZpbHRlcihjbGFzc2lmaWNhdGlvbiA9PSAiUG9vci1wZXJmb3JtaW5nIikKCiMgam9pbiBoaWdoIHBlcmZvcm1pbmcgd2l0aCBsYWJlbApzaV9kYy5oaWdoIDwtIHNpX2RjLmhpZ2ggJT4lIGxlZnRfam9pbihlel9sYWJlbCAlPiUgZGlzdGluY3QobGFiZWxfc2ksIC5rZWVwX2FsbCA9IFQpLCBieSA9IGMoImlkIiA9ICJpZF9zaSIpKQoKI3dyaXRlX3BhcnF1ZXQoc2lfZGMuaGlnaCwgaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL3NpX2RjX2hpZ2gucGFycXVldCIpKQojd3JpdGVfcGFycXVldChzaV9kYy5wb29yLCBoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvc2lfZGNfcG9vci5wYXJxdWV0IikpCmBgYAoKIy0tLS0tLS0tLSBkdWFsIGN1ZSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSMKIyBwcm9jZXNzIGRhdGEKYGBge3J9CiMgdHVybiBza2lubnkKZHVhbF9kYy5kZiA8LSBkdWFsX2R5bi5kZiAlPiUgCiAgbXV0YXRlKGxhYmVsX2FsdCA9IHBhc3RlKGxhYmVsLCAiKyIgLCBsYWJlbF9iKSkgJT4lIAogIHNlbGVjdChsYWJlbF9hbHQsIHRpbWUsIHZhcmlhYmxlLCB2YWx1ZSkgJT4lIAogIGZpbHRlcih2YXJpYWJsZSA9PSAiSSIgfCB2YXJpYWJsZSA9PSAiSWciIHwgdmFyaWFibGUgPT0gIlIiKSAlPiUgCiAgZGlzdGluY3QobGFiZWxfYWx0LCB0aW1lLCB2YXJpYWJsZSwgLmtlZXBfYWxsID0gVCkKCmR1YWxfZHluLmRmCgpkdWFsX2RjLmRmMiA8LSBkdWFsX2RjLmRmICU+JSAKICB0aWR5cjo6cGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHZhcmlhYmxlLCB2YWx1ZXNfZnJvbSA9IHZhbHVlLCBpZF9jb2xzID0gYyh0aW1lLCBsYWJlbF9hbHQpKSAlPiUKICBtdXRhdGUodG90YWwgPSBJK0lnKQoKI3dyaXRlX3BhcnF1ZXQoZHVhbF9kYy5kZjIsIGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9kdWFsX2RjLnBhcnF1ZXQiKSkKCiMgZ29vZCBkdWFsIGN1ZSAtPiBsaXN0IG9mIGdvb2QgcGVyZm9ybWluZyBkdWFsIGN1ZXMgdGhhdCBlbmNvbXBhc3Mgd2lkZSB2YXJpZXR5IG9mIGN1ZXMKc2VsZWN0ZWRfZHVhbF9jdWUgPC0gYygiUiBsb2cgKyBJIGxvZyIsICJSICsgSWcgbG9nIiwgIkcgbG9nICsgSSBsb2ciLCAiRyBsb2cgKyBJZyBsb2ciLCAiSWcgKyBJIGxvZyIpCmJhZF9kdWFsX2N1ZSA8LSBjKCJHICsgSSIsICJSICsgSWciLCAiUiBsb2cgKyBJZyIsICJHICsgUiIsICJHICsgUiBsb2ciLCAiRyArIElnIiwgIklnICsgSSIsICJSICsgSSIsICJSIGxvZyArIEkiKQoKIyBnZXQgY2xhc3NpZmljYXRpb24gLT4gUiBsb2cxMCArIEkgbG9nMTAgYXMgdGhlIG9ubHkgZ29vZCBvbmUKZHVhbF9kYy5oaWdoIDwtIGR1YWxfZGMuZGYyICU+JSBmaWx0ZXIobGFiZWxfYWx0ICVpbiUgc2VsZWN0ZWRfZHVhbF9jdWUpICU+JSAKICBtdXRhdGUobGFiZWxfYWx0ID0gZ3N1YigibG9nIiwgImxvZzEwIiwgbGFiZWxfYWx0KSkKZHVhbF9kYy5wb29yIDwtIGR1YWxfZGMuZGYyICU+JSBmaWx0ZXIobGFiZWxfYWx0ICVpbiUgYmFkX2R1YWxfY3VlKSAlPiUgCiAgbXV0YXRlKGxhYmVsX2FsdCA9IGdzdWIoImxvZyIsICJsb2cxMCIsIGxhYmVsX2FsdCkpCiN3cml0ZV9wYXJxdWV0KGR1YWxfZGMuaGlnaCwgaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL2R1YWxfZGNfaGlnaC5wYXJxdWV0IikpCiN3cml0ZV9wYXJxdWV0KGR1YWxfZGMucG9vciwgaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL2R1YWxfZGNfcG9vci5wYXJxdWV0IikpCgpgYGAKCiMtLS0tLS0tIHBsb3R0aW5nIHNpbmdsZSBhbmQgZHVhbCBjdWUgZGlzZWFzZSBtYXAgdG9nZXRoZXItLS0tLS0tIwojIHBsb3QKYGBge3J9CiMgaW1wb3J0IHNpbmdsZSBpbmZlY3Rpb24gZGF0YQpzaV9kYy5wb29yIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvc2lfZGNfcG9vci5wYXJxdWV0IikpCnNpX2RjLmhpZ2ggPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9zaV9kY19oaWdoLnBhcnF1ZXQiKSkKCiMgaW1wb3J0IGR1YWwgY3VlIGRhdGEKZHVhbF9kYy5oaWdoIDwtIHJlYWRfcGFycXVldChoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvZHVhbF9kY19oaWdoLnBhcnF1ZXQiKSkKZHVhbF9kYy5oaWdoMiA8LSBkdWFsX2RjLmhpZ2ggJT4lIAogIGZpbHRlcihsYWJlbF9hbHQgPT0gIlIgbG9nMTAgKyBJIGxvZzEwIikKCiMgcGxvdCBiYWNrZ3JvdW5kIGR5bmFtaWNzCnNpX2RjLnByZSA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBzaV9kYy5wb29yLCBhZXMoeD0gdG90YWwsIHkgPSBSLCBncm91cCA9IGlkKSwgY29sb3IgPSAiZGFyayBncmV5IiwgYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgbGFicyhjb2xvciA9ICJTaW5nbGUgaW5mZWN0aW9uXG5nb29kIHBlcmZvcm1pbmcgY3VlcyIsIHggPSAiQXNleHVhbCAmIHNleHVhbCBpUkJDIHBlciDCtUwiLCB5ID0gIlJCQyBwZXIgwrVMIikgKwogIHRoZW1lX2J3KCkrIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFRSVUUsIGFjY3VyYWN5ID0gMC4xKSkgKwogIGd1aWRlcyhzaGFwZSA9IEZBTFNFKQoKIyBwbG90IGNvbG9yZWQgZHluYW1pY3MKIyMgY29tYmluZSBzaW5nbGUgYW5kIGR1YWwgY3VlIGR5bmFtaWNzCnNpX2RjLmhpZ2gyIDwtIHJiaW5kKHNlbGVjdChzaV9kYy5oaWdoLCBlel9sYWJlbCwgdG90YWwsIFIsIHRpbWUpLAogICAgICBzZWxlY3QoZHVhbF9kYy5oaWdoMiwgZXpfbGFiZWwgPSBsYWJlbF9hbHQsIHRvdGFsLCBSLCB0aW1lKSkKCnNpX2RjLnBsIDwtIHNpX2RjLnByZSArCiAgZ2VvbV9wb2ludChkYXRhID0gc2lfZGMuaGlnaDIgJT4lIGZpbHRlcihyb3dfbnVtYmVyKCkgJSUgMTAwMCA9PTApLCBhZXMoeCA9IHRvdGFsLCB5ID0gUiwgY29sb3IgPSBlel9sYWJlbCwgc2hhcGUgPSBlel9sYWJlbCksIHNpemUgPSAzKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBzaV9kYy5oaWdoMiwgYWVzKHg9IHRvdGFsLCB5ID0gUiwgZ3JvdXAgPSBlel9sYWJlbCwgY29sb3IgPSBlel9sYWJlbCksIHNpemUgPSAxLCBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwgYW5nbGUgPSAxMCwgbGVuZ3RoID0gdW5pdCgwLjIsICJpbmNoZXMiKSkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoICIjNDU3NWI0IiwgIiNmZGNiNDQiLCAiIzkxYmZkYiIsImJsYWNrIiwgIiNmYzhkNTkiKSkgICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikgKwogIGxhYnMoY29sb3IgPSAiQ3VlcyIpICsKICBndWlkZXMoY29sb3I9Z3VpZGVfbGVnZW5kKG5yb3c9MixieXJvdz1UUlVFKSkKYGBgCgojLS0tLS0tLS0tLSBjby1pbmZlY3Rpb24gbW9ub2N1ZSAtLS0tLS0tLS0tLS0tIwpOb3RlIHRoYXQgd2UgYXJlIHBsb3R0aW5nIG9ubHkgc2luZ2xlIHN0cmFpbiB0byBzaG93IHRoYXQgb24gYSBzaW5nbGUgc3RyYWluIGxldmVsLCBjby1pbmZlY3Rpb24gbGVhZHMgdG8gbGFyZ2VyIGFyZWEgdGhhbiBzaW5nbGUgaW5mZWN0aW9uIQojIHByb2Nlc3MgZGF0YQpgYGB7cn0KIyBnZXQgcmVsZXZlbnQgdmFyaWFibGVzLiAKY2lfZGMuZGYgPC0gY2lfZHluLmRmICU+JSAKICBmaWx0ZXIodmFyaWFibGUgJWluJSBjKCJJMSIsICJJZzEiLCAiUiIpKQoKIyBtb3JwaCBpbnRvIHNraW5ueSBmb3JtYXQKY2lfZGMuZGYgPC0gdGlkeXI6OnBpdm90X3dpZGVyKGNpX2RjLmRmLCBuYW1lc19mcm9tID0gdmFyaWFibGUsIHZhbHVlc19mcm9tID0gdmFsdWUsIGlkX2NvbHMgPSBjKHRpbWUsIGxhYmVsKSkgJT4lIAogIG11dGF0ZSh0b3RhbCA9IEkxK0lnMSkKCiMgZ29vZCBjdWUgYmFkIGN1ZQpjaV9jdWUuZHYgPC0gY2lfZml0bmVzcy5kZiAlPiUgCiAgbXV0YXRlKGNsYXNzaWZpY2F0aW9uID0gY2FzZV93aGVuKAogICAgdmFsdWUgPiAyLjI1IH4gIkhpZ2gtcGVyZm9ybWluZyIsCiAgICB2YWx1ZSA8PSAyLjI1IH4gIlBvb3ItcGVyZm9ybWluZyIKICApKQoKIyBqb2luIHdpdGggY2xhc3NpZmljYWl0b24KY2lfZGMuZGYyIDwtIGNpX2RjLmRmICU+JSBsZWZ0X2pvaW4oY2lfY3VlLmR2LCBieSA9ICJsYWJlbCIpCgojIHNwbGl0IGludG8gdG9wIGVyZm9ybWluZyBhbmQgcG9vci1wZXJmb3JtaW5nIGN1ZXMKY2lfZGMuaGlnaCA8LSBjaV9kYy5kZjIgJT4lIGZpbHRlcihjbGFzc2lmaWNhdGlvbiA9PSAiSGlnaC1wZXJmb3JtaW5nIikKY2lfZGMucG9vciA8LSBjaV9kYy5kZjIgJT4lIGZpbHRlcihjbGFzc2lmaWNhdGlvbiA9PSAiUG9vci1wZXJmb3JtaW5nIikKCiMgam9pbiBoaWdoIHBlcmZvcm1pbmcgd2l0aCBsYWJlbApjaV9kYy5oaWdoMiA8LSBjaV9kYy5oaWdoICU+JSBsZWZ0X2pvaW4oZXpfbGFiZWwsIGJ5ID0gYygibGFiZWwiID0gImxhYmVsX2NpIikpCgp3cml0ZV9wYXJxdWV0KGNpX2RjLmhpZ2gyLCBoZXJlKCJkYXRhL2Rpc2Vhc2VfY3VydmUvY2lfZGNfaGlnaC5wYXJxdWV0IikpCndyaXRlX3BhcnF1ZXQoY2lfZGMucG9vciwgaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL2NpX2RjX3Bvb3IucGFycXVldCIpKQpgYGAKCiMgcGxvdApgYGB7cn0KY2lfZGMucG9vciA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL2NpX2RjX3Bvb3IucGFycXVldCIpKQpjaV9kYy5oaWdoMiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL2NpX2RjX2hpZ2gucGFycXVldCIpKQoKIyBwbG90CmNpX2RjLnByZSA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBjaV9kYy5wb29yLCBhZXMoeD0gdG90YWwsIHkgPSBSLCBncm91cCA9IGxhYmVsKSwgY29sb3IgPSAiZGFyayBncmV5IiwgYXJyb3cgPSBhcnJvdyh0eXBlID0gImNsb3NlZCIsIGFuZ2xlID0gMTAsIGxlbmd0aCA9IHVuaXQoMC4yLCAiaW5jaGVzIikpKSArCiAgbGFicyhjb2xvciA9ICJDdWVzIiwgeCA9ICJBc2V4dWFsICYgc2V4dWFsIGlSQkMgcGVyIMK1TCAocGVyIHN0cmFpbikiLCB5ID0gIlJCQyBwZXIgwrVMIikgKwogIHRoZW1lX2J3KCkrIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IFRSVUUsIGFjY3VyYWN5ID0gMC4xKSkgKwogIGd1aWRlcyhzaGFwZSA9IEZBTFNFKQoKY2lfZGMucGwgPC0gY2lfZGMucHJlICsKICBnZW9tX3BvaW50KGRhdGEgPSBjaV9kYy5oaWdoMiAlPiUgZmlsdGVyKHJvd19udW1iZXIoKSAlJSAxMDAwID09MCksIGFlcyh4ID0gdG90YWwsIHkgPSBSLCBjb2xvciA9IGV6X2xhYmVsLCBzaGFwZSA9IGV6X2xhYmVsKSwgc2l6ZSA9IDMpICsKICBnZW9tX3BhdGgoZGF0YSA9IGNpX2RjLmhpZ2gyLCBhZXMoeD0gdG90YWwsIHkgPSBSLCBncm91cCA9IGV6X2xhYmVsLCBjb2xvciA9IGV6X2xhYmVsKSwgc2l6ZSA9IDEsIGFycm93ID0gYXJyb3codHlwZSA9ICJjbG9zZWQiLCBhbmdsZSA9IDEwLCBsZW5ndGggPSB1bml0KDAuMiwgImluY2hlcyIpKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YyggIiM0NTc1YjQiLCAiI2ZjOGQ1OSIsICIjZmRjYjQ0IiwgIiM5MWJmZGIiKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSArCiAgZ3VpZGVzKGNvbG9yPWd1aWRlX2xlZ2VuZChucm93PTIsYnlyb3c9VFJVRSkpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgZm9ybWF0KHgsIHNjaWVudGlmaWMgPSBUUlVFLCBhY2N1cmFjeSA9IDAuMSkpCgpgYGAKCiMtLS0tLS0tLS0gcXVhbnRpZnlpbmcgZGlzZWFzZSBjdXJ2ZSBhcmVhIC0tLS0tLS0tLS0tLSMKIyBmdW5jdGlvbiB0byBjYWxjdWxhdGUgYXJlYSBiZXR3ZWVuIHNldHMgb2YgcG9pbnRzIC0+IGZyb20gaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMzY3MjI2MC9hcmVhLWNvdmVyZWQtYnktYS1wb2ludC1jbG91ZC13aXRoLXIKYGBge3J9CmxpYnJhcnkoc3BsYW5jcykKY2hhPC1mdW5jdGlvbihkZil7CiAgeCA8LSBkZiR0b3RhbAogIHkgPC0gZGYkUgpjaHVsbCh4LHkpLT5pCnJldHVybihhcmVhcGwoY2JpbmQoeFtpXSx5W2ldKSkpCn0KYGBgCgojIGxvb3AgdG8gZ2V0IGFyZWE6IHNpbmdsZSBpbmZlY3Rpb24KYGBge3J9CiMgc3BsaXQgZGYKc2lfZGMubHMgPC0gc3BsaXQoc2lfZGMuZGYsIHNpX2RjLmRmJGlkKQoKIyBnZXQgYXJlYQpzaV9kYy5hcmVhIDwtIGNiaW5kLmRhdGEuZnJhbWUoYXJlYSA9IGFzLm51bWVyaWMobGFwcGx5KHNpX2RjLmxzLCBjaGEpKSwgaWRfYWx0ID0gbmFtZXMobGFwcGx5KHNpX2RjLmxzLCBjaGEpKSkKCiMgam9pbiB3aXRoIGZpdG5lc3MKc2lfZml0bmVzcy5kZjIgPC0gc2lfZml0bmVzcy5kZiAlPiUgCiAgc2VsZWN0KGlkLCBmaXRuZXNzID0gdmFsdWUpICU+JSAKICBkaXN0aW5jdChpZCwgZml0bmVzcykgJT4lIAogIGxlZnRfam9pbihlel9sYWJlbCwgYnkgPSBjKCJpZCIgPSAiaWRfc2kiKSkKCnNpX2RjLmFyZWEgPC0gc2lfZGMuYXJlYSAlPiUgCiAgbGVmdF9qb2luKHNpX2ZpdG5lc3MuZGYyLCBieSA9IGMoImlkX2FsdCIgPSAiaWQiKSkKYGBgCgojIGR1YWwgY3VlCmBgYHtyfQojIHNwbGl0CmR1YWwuZGMgPC0gcmVhZF9wYXJxdWV0KGhlcmUoImRhdGEvZGlzZWFzZV9jdXJ2ZS9kdWFsX2RjLnBhcnF1ZXQiKSkKCiMgZ2V0IGFyZWEKZHVhbF9kYy5hcmVhIDwtIGNiaW5kLmRhdGEuZnJhbWUoYXJlYSA9IGFzLm51bWVyaWMobGFwcGx5KGR1YWxfZGMubHMsIGNoYSkpLCBpZF9hbHQgPSBuYW1lcyhsYXBwbHkoZHVhbF9kYy5scywgY2hhKSkpCgojIGdldCBSIGxvZytJIGxvZyBhcmVhOiAyOTM2MzI4NTA1NDEKZHVhbF9kYy5hcmVhICU+JSBmaWx0ZXIoaWRfYWx0ID09ICJSIGxvZyArIEkgbG9nIikKYGBgCgojIGNvaW5mZWN0aW9uCmBgYHtyfQojIHNwbGl0CmNpX2RjLmxzIDwtIHNwbGl0KGNpX2RjLmRmLCBjaV9kYy5kZiRsYWJlbCkKCiMgcnVuIGZ1bmN0aW9uIHRvIGZpbmQgYXJlYQpjaV9kYy5hcmVhIDwtIGNiaW5kLmRhdGEuZnJhbWUoYXJlYSA9IGFzLm51bWVyaWMobGFwcGx5KGNpX2RjLmxzLCBjaGEpKSwgaWRfYWx0ID0gbmFtZXMobGFwcGx5KGNpX2RjLmxzLCBjaGEpKSkKCiMgam9pbiB3aXRoIGZpdG5lc3MKY2lfZGMuYXJlYSA8LSBjaV9kYy5hcmVhICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGNpX2ZpdG5lc3MuZGYsIGxhYmVsLCBmaXRuZXNzID0gdmFsdWUpLCBieSA9IGMoImlkX2FsdCIgPSAibGFiZWwiKSkKY2lfZGMuYXJlYQpgYGAKCiMtLS0tLS0gZ2V0IGZpdHRlZCBzY2F0dGVyIHBsb3QgZm9yIGFsbCBzaW5nbGUgaW5mZWN0aW9uLCBjbyBpbmZlY3Rpb24sIGFuZCBkdWFsIGN1ZSAtLS0tLS0tLSMKYGBge3J9CiMgIGNvbWJpbmUgc2luZ2xlIGFuZCBkdWFsIGN1ZQpzaV9kdWFsLmFyZWEgPC0gc2VsZWN0KHNpX2RjLmFyZWEsIGV6X2xhYmVsX3NpLCBhcmVhLCBmaXRuZXNzKSAlPiUgcmJpbmQoZGF0YS5mcmFtZShlel9sYWJlbF9zaSA9ICJSQkMgbG9nMTAgK1xuYXNleHVhbCBpUkJDIGxvZzEwIiwgYXJlYSA9IDI5MzYzMjg1MDU0MSwgZml0bmVzcyA9IDkuODUxNzM1KSkKCnNpX2R1YWwuYXJlYSRhcmVhIDwtIGFzLm51bWVyaWMoc2lfZHVhbC5hcmVhJGFyZWEpCnNpX2R1YWwuYXJlYSRmaXRuZXNzIDwtIGFzLm51bWVyaWMoc2lfZHVhbC5hcmVhJGZpdG5lc3MpCgojIHBsb3QKbGlicmFyeSgiZ2dwbWlzYyIpCgpzaV9hcmVhLnBsIDwtIGdncGxvdChkYXRhID0gc2lfZHVhbC5hcmVhLCBhZXMoeCA9IGFyZWEsIHkgPSBmaXRuZXNzKSkgKwogIGdlb21fcG9pbnQoKSArCiAgc3RhdF9wb2x5X2xpbmUoY29sb3IgPSAiYmxhY2siKSArCiAgc3RhdF9wb2x5X2VxKCkgKwogIGxhYnMoeCA9ICJBcmVhIiwgeSA9ICJGaXRuZXNzIikgKwogIHRoZW1lX2J3KCkKCmNpX2FyZWEucGwgPC0gZ2dwbG90KGRhdGEgPSBjaS5hcmVhLCBhZXMoeCA9IGFyZWEsIHkgPSB2YWx1ZSkpICsKICBnZW9tX3BvaW50KCkgKwogIHN0YXRfcG9seV9saW5lKGNvbG9yID0gImJsYWNrIikgKwogIHN0YXRfcG9seV9lcSgpICsKICBsYWJzKHggPSAiQXJlYSIsIHkgPSAiRml0bmVzcyIsIGNvbG9yID0gIlN0YXR1cyIpICsKICB0aGVtZV9idygpCgpgYGAKCgojLS0tLS0tLSBwbG90IHRvZ2V0aGVyIHdpdGggZGlzZWFzZSBjdXJ2ZSAtLS0tLS0tLSMKYGBge3J9CiMgc2luZ2xlIGluZmVjdGlvbgpzaV92aXIucGwgPC0gZ2dhcnJhbmdlKHNpX2RjLnBsLCBzaV9hcmVhLnBsLCBhbGlnbiA9ICJ2Iiwgd2lkdGhzID0gYygxLCAwLjUpKQoKIyBjby1pbmZlY3Rpb24KY2lfdmlyLnBsIDwtIGdnYXJyYW5nZShjaV9kYy5wbCwgY2lfYXJlYS5wbCwgYWxpZ24gPSAidiIsIHdpZHRocyA9IGMoMSwgMC41KSkKYGBgCgoKIy0tLS0tLS0tLSBzdGF0aWMgYXJlYSBjb21wYXJpc29uIC0tLS0tLS0tLS0tLS0jCiMgY29tcHV0ZSBhcmVhCmBgYHtyfQojIGltcG9ydCBpbiBkYyBkeW5hbWljIGFuZCBmaXRuZXNzCnN0YXRpY19kYy5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL3N0YXRpY19kYy5wYXJxdWV0IikpCnN0YXRpY19maXRuZXNzLmRmIDwtIHJlYWQuY3N2KGhlcmUoImRhdGEvY2lfc3RhdGljLmNzdiIpKQoKIyBnZXQgd2lubmVyIGFuZCBsb3NlcgpzdGF0aWNfZGMuZGY0IDwtIHN0YXRpY19kYy5kZiAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChzdGF0aWNfZml0bmVzcy5kZiwgaWRfMSwgaWRfMiwgZml0bmVzc19kaWZmZXJlbmNlKSwgYnkgPSBjKCJpZF8xIiwgImlkXzIiKSkgJT4lCiAgZmlsdGVyKGlkXzEgIT0gaWRfMikgJT4lIAogIG11dGF0ZSgKICB0b3RhbF93aW5uZXIgPSBjYXNlX3doZW4oCiAgICBmaXRuZXNzX2RpZmZlcmVuY2UgPiAwIH4gdG90YWwxLAogICAgZml0bmVzc19kaWZmZXJlbmNlPCAwIH4gdG90YWwyCiAgKSwKICB0b3RhbF9sb3NlciA9IGNhc2Vfd2hlbigKICAgIGZpdG5lc3NfZGlmZmVyZW5jZSA+IDAgfiB0b3RhbDIsCiAgICBmaXRuZXNzX2RpZmZlcmVuY2U8IDAgfiB0b3RhbDEKICApKSU+JSAKICBmaWx0ZXIoYWJzKGZpdG5lc3NfZGlmZmVyZW5jZSkgPiAwLjEpCgojIHNwbGl0IGJ5IHdpbm5lciBhbmQgbG9zZXIKc3RhdGljX2RjLmxzMSA8LSBzcGxpdChzZWxlY3Qoc3RhdGljX2RjLmRmNCwgUiwgdG90YWwgPSB0b3RhbF93aW5uZXIpLCBzdGF0aWNfZGMuZGY0JGlkX2FsdCkKc3RhdGljX2RjLmxzMiA8LSBzcGxpdChzZWxlY3Qoc3RhdGljX2RjLmRmNCwgUiwgdG90YWwgPSB0b3RhbF9sb3NlciksIHN0YXRpY19kYy5kZjQkaWRfYWx0KQoKIyBnZXQgYXJlYQpzdGF0aWNfd2luLmFyZWEgPC0gY2JpbmQuZGF0YS5mcmFtZShhcmVhID0gYXMubnVtZXJpYyhsYXBwbHkoc3RhdGljX2RjLmxzMSwgY2hhKSksIHN0YXR1cyA9ICJXaW5uZXIiKQpzdGF0aWNfbG9zZXIuYXJlYSA8LSBjYmluZC5kYXRhLmZyYW1lKGFyZWEgPSBhcy5udW1lcmljKGxhcHBseShzdGF0aWNfZGMubHMyLCBjaGEpKSwgc3RhdHVzID0gIkxvc2VyIikKCiMgcGFpcgpzdGF0aWMuYXJlYSA8LSBjYmluZChzZWxlY3Qoc3RhdGljX3dpbi5hcmVhLCBXaW5uZXIgPSBhcmVhKSwKICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHN0YXRpY19sb3Nlci5hcmVhLCBMb3NlciA9IGFyZWEpKSAlPiUgCiAgbXV0YXRlKGNsYXNzaWZpY2F0aW9uID0gaWZlbHNlKFdpbm5lcj5Mb3NlciwgIldpbm5lciBsYXJnZXIgYXJlYSIsICJMb3NlciBsYXJnZXIgYXJlYSIpKQpzdGF0aWMuYXJlYSAKYGBgCgojIHBsb3Qgc3RhdGljCmBgYHtyfQpzdGF0aWMuYXJlYQpzdGF0aWNfYXJlYS5wbCA8LSBnZ3BhaXJlZChzdGF0aWMuYXJlYSwgY29uZDEgPSAiV2lubmVyIiwgY29uZDIgPSAiTG9zZXIiLCBsaW5lLmNvbG9yID0gImNsYXNzaWZpY2F0aW9uIiwgYWxwaGEgPSAwLjIpICsKICBsYWJzKHggPSAiU3RhdHVzIiwgeSA9ICJBcmVhIiwgY29sb3IgPSAiQ29tcGFyaXNvblxuKFN0YXRpYykiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIkxvc2VyIGxhcmdlciBhcmVhIiA9ICIjZmM4ZDU5IiwgIldpbm5lciBsYXJnZXIgYXJlYSIgPSAiIzQ1NzViNCIpKSArCiAgc3RhdF9jb21wYXJlX21lYW5zKHBhaXJlZCA9IFRSVUUsIGhqdXN0ID0gMCkgKwogIGd1aWRlcyhjb2xvcj1ndWlkZV9sZWdlbmQobnJvdz0yLGJ5cm93PVRSVUUpKQpgYGAKCgojLS0tLS0tLS0tIGludmFzaW9uIGFyZWEgY29tcGFyaXNvbiAtLS0tLS0tLS0tLS0tLS0tLSMKIyBnZXQgYXJlYQpgYGB7cn0KIyBpbXBvcnQgaW4gZGMgZHluYW1pYyBhbmQgZml0bmVzcwppbnZhc2lvbl9kYy5kZiA8LSByZWFkX3BhcnF1ZXQoaGVyZSgiZGF0YS9kaXNlYXNlX2N1cnZlL2ludmFzaW9uX2RjLnBhcnF1ZXQiKSkKaW52YXNpb25fZml0bmVzcy5kZiA8LSByZWFkLmNzdihoZXJlKCJkYXRhL2NpX2ludmFzaW9uLmNzdiIpKQoKIyBjYWxjdWxhdGUgYXJlYQppbnZhc2lvbl9kYy5kZjQgPC0gaW52YXNpb25fZGMuZGYgJT4lIAogIGxlZnRfam9pbihpbnZhc2lvbl9maXRuZXNzLmRmLCBieSA9IGMoIm11dF9pZCIsICJyZXNfaWQiKSkgJT4lIAogIG11dGF0ZSgKICB0b3RhbF93aW5uZXIgPSBjYXNlX3doZW4oCiAgICBmaXRuZXNzPiAwIH4gdG90YWwxLAogICAgZml0bmVzczwgMCB+IHRvdGFsMgogICksCiAgdG90YWxfbG9zZXIgPSBjYXNlX3doZW4oCiAgICBmaXRuZXNzID4gMCB+IHRvdGFsMiwKICAgIGZpdG5lc3MgPCAwIH4gdG90YWwxCiAgKSkgJT4lIAogIGZpbHRlcihhYnMoZml0bmVzcykgPiAwLjEpCgppbnZhc2lvbl9kYy5kZjQgJT4lIGRpc3RpbmN0KGlkX2FsdCkKCiMgc3BsaXQgYnkgd2lubmVyIGFuZCBsb3NlcgppbnZhc2lvbl9kYy5sczEgPC0gc3BsaXQoc2VsZWN0KGludmFzaW9uX2RjLmRmNCwgUiwgdG90YWwgPSB0b3RhbF93aW5uZXIpLCBpbnZhc2lvbl9kYy5kZjQkaWRfYWx0KQppbnZhc2lvbl9kYy5sczIgPC0gc3BsaXQoc2VsZWN0KGludmFzaW9uX2RjLmRmNCwgUiwgdG90YWwgPSB0b3RhbF9sb3NlciksIGludmFzaW9uX2RjLmRmNCRpZF9hbHQpCgojIGdldCBhcmVhCmludmFzaW9uX3dpbi5hcmVhIDwtIGNiaW5kLmRhdGEuZnJhbWUoYXJlYSA9IGFzLm51bWVyaWMobGFwcGx5KGludmFzaW9uX2RjLmxzMSwgY2hhKSksIHN0YXR1cyA9ICJXaW5uZXIiKQppbnZhc2lvbl9sb3Nlci5hcmVhIDwtIGNiaW5kLmRhdGEuZnJhbWUoYXJlYSA9IGFzLm51bWVyaWMobGFwcGx5KGludmFzaW9uX2RjLmxzMiwgY2hhKSksIHN0YXR1cyA9ICJMb3NlciIpCgojIHBhaXIKaW52YXNpb24uYXJlYSA8LSBjYmluZChzZWxlY3QoaW52YXNpb25fd2luLmFyZWEsIFdpbm5lciA9IGFyZWEpLAogICAgICAgICAgICAgICAgICAgICBzZWxlY3QoaW52YXNpb25fbG9zZXIuYXJlYSwgTG9zZXIgPSBhcmVhKSkgJT4lIAogIG11dGF0ZShjbGFzc2lmaWNhdGlvbiA9IGlmZWxzZShXaW5uZXI+TG9zZXIsICJXaW5uZXIgbGFyZ2VyIGFyZWEiLCAiTG9zZXIgbGFyZ2VyIGFyZWEiKSkKaW52YXNpb24uYXJlYQpgYGAKCiMgcGxvdApgYGB7cn0KaW52YXNpb25fYXJlYS5wbCA8LWdncGFpcmVkKGludmFzaW9uLmFyZWEsIGNvbmQxID0gIldpbm5lciIsIGNvbmQyID0gIkxvc2VyIiwgbGluZS5jb2xvciA9ICJjbGFzc2lmaWNhdGlvbiIsIGFscGhhID0gMC4yKSArCiAgbGFicyh4ID0gIlN0YXR1cyIsIHkgPSAiQXJlYSIsIGNvbG9yID0gIkNvbXBhcmlzb25cbihJbnZhc2l2ZSkiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIkxvc2VyIGxhcmdlciBhcmVhIiA9ICIjZmM4ZDU5IiwgIldpbm5lciBsYXJnZXIgYXJlYSIgPSAiIzQ1NzViNCIpKSArCiAgc3RhdF9jb21wYXJlX21lYW5zKHBhaXJlZCA9IFRSVUUsIGhqdXN0ID0gMCkgKwogIGd1aWRlcyhjb2xvcj1ndWlkZV9sZWdlbmQobnJvdz0yLGJ5cm93PVRSVUUpKQpgYGAKCiMtLS0tLS0gcGxvdCB0b2dldGhlciAtLS0tLS0tLS0tLS0tIwpgYGB7cn0KIyBkaXNlYXNlIGN1cnZlcwpkYy5wbCA8LSBnZ2FycmFuZ2Uoc2lfdmlyLnBsLCBjaV92aXIucGwsIG5jb2wgPSAxLCBucm93ID0gMiwgYWxpZ24gPSAidiIsIGxhYmVscyA9IGMoIkEiLCAiQiIpKQoKIyBwYWlyd2lzZSBjb21wYXJpc29uIGZvciBzdGF0aWMgYW5kIGludmFzaXZlIGNvbWVwdGl0aW9uCmhldGVyb2N1ZV9jb21wLnBsIDwtIGdnYXJyYW5nZShzdGF0aWNfYXJlYS5wbCwgaW52YXNpb25fYXJlYS5wbCwgbmNvbCA9IDEsIG5yb3cgPSAyLCBhbGlnbiA9ICJ2IiwgbGFiZWxzID0gYygiQyIsICJEIikpCgojIGpvaW4gaW50aGUgb3RoZXIgZGlzZWFzZSBjdXJ2ZXMKZ2dhcnJhbmdlKGRjLnBsLCBoZXRlcm9jdWVfY29tcC5wbCwgbmNvbCA9IDIsIG5yb3cgPSAxLCB3aWR0aHM9IGMoMSwgMC41KSkKCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3Bsb3MtYmlvL3ZpcnVsZW5jZS50aWZmIiksIHVuaXRzID0gInB4Iiwgd2lkdGggPSAyMzAwLCBoZWlnaHQgPSAyMDAwLCBzY2FsZSA9IDEuNSwgZHBpPTMwMCwgYmcgPSAid2hpdGUiKQpgYGAKCgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwojIGR1YWwgY3VlIGR5bmFtaWNzIGZpZ3VyZQojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCgojIGdldCBkdWFsIGR5bmFtaWNzCmBgYHtyfQpkdWFsLmR5biA8LSBjaGFiYXVkaV9zaV9jbGVhbigKICBwYXJhbWV0ZXJzX2NyID0gYyg0LjQ0NjE5MjAzMywJMTAuOTc1MTgyNzUsCTEuMzg3NjI4MTcsCTIzLjMwNTkyNTQsCS0zLjQ1MjA1MjM3MSwJLTE4LjAwNzA2OTIsCTM5LjY2NjE0MjI2LAktMy41NDUxOTMxNDEsCTE4Ljc4MzUwNzk5KSwKICBpbW11bml0eSA9ICJ0c3VrdXNoaSIsCiAgcGFyYW1ldGVycyA9IHBhcmFtZXRlcnNfdHN1a3VzaGksCiAgdGltZV9yYW5nZSA9IHNlcSgwLCAzMCwgYnkgPSAxZS0zKSwKICBjdWVfcmFuZ2UgPSAgc2VxKDYsIDcsIGJ5ID0gMS81MDApLAogIGN1ZV9yYW5nZV9iID0gc2VxKDAsIGxvZzEwKDYqKDEwXjYpKSwgYnkgPSAobG9nMTAoNiooMTBeNikpKS81MDApLAogIGN1ZSA9ICJSIiwKICBjdWVfYiA9ICJJIiwKICBsb2dfY3VlID0gImxvZzEwIiwKICBsb2dfY3VlX2IgPSAibG9nMTAiLAogIHNvbHZlciA9ICJ2b2RlIiwKICBkeW4gPSBUCikKCiMgZmlsdGVyIG91dCByZWxldmVudCBkYXRhZnJhbWVzCmR1YWwuZHluX2YgPC0gZHVhbC5keW4gJT4lIAogIGZpbHRlcih2YXJpYWJsZSAlaW4lIGMoIkkiLCAiSWciLCAiRyIsICJSIiwgIk4iLCAiVyIpKQoKIyBjciBvbmx5CmR1YWwuZHluX2NyIDwtIGR1YWwuZHluICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gImNyIikKYGBgCgojIHBsb3QKYGBge3J9CmR1YWxfSS5wbHQgPC0gZ2dwbG90KCkgKwogIGdlb21fbGluZShkYXRhID0gZHVhbC5keW5fZiAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJJIiksIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlLygxMF41KSksCiAgICAgICAgICAgIGNvbG9yID0gIiM0NTc1YjQiKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZHVhbC5keW5fZiAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJJIiAmIHJvd19udW1iZXIoKSAlJSAxMDAwID09IDApLCAKICAgICAgICAgICAgIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlLygxMF41KSksIHNpemUgPSAyLCBjb2xvciA9ICIjNDU3NWI0IikgKwogIGdlb21fbGluZShkYXRhID0gZHVhbC5keW5fY3IsIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlKSkgKwogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIkNvbnZlcnNpb24gcmF0ZSIsCiAgICAgICAgICAgICAgICAgICAgIHNlYy5heGlzID0gc2VjX2F4aXMofi4qMTBeNSwgbmFtZT0iQXNleHVhbCBpUkJDIHBlciDCtUwiKSkgKwogIGxhYnMoeCA9ICJUaW1lIChkYXlzKSIpICsKICB4bGltKDAsIDIwKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKZHVhbF9JZy5wbHQgPC1nZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBkdWFsLmR5bl9mICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gIklnIiksIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlLygxMF41KSksCiAgICAgICAgICAgIGNvbG9yID0gIiM0NTc1YjQiKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZHVhbC5keW5fZiAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJJZyIgJiByb3dfbnVtYmVyKCkgJSUgMTAwMCA9PSAwKSwgCiAgICAgICAgICAgICBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZS8oMTBeNSkpLCBzaXplID0gMiwgY29sb3IgPSAiIzQ1NzViNCIpICsKICBnZW9tX2xpbmUoZGF0YSA9IGR1YWwuZHluX2NyLCBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobmFtZSA9ICJDb252ZXJzaW9uIHJhdGUiLAogICAgICAgICAgICAgICAgICAgICBzZWMuYXhpcyA9IHNlY19heGlzKH4uKjEwXjUsIG5hbWU9IlNleHVhbCBpUkJDIHBlciDCtUwiKSkgKwogIGxhYnMoeCA9ICJUaW1lIChkYXlzKSIpICsKICB4bGltKDAsIDIwKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKZHVhbF9HLnBsdCA8LWdncGxvdCgpICsKICBnZW9tX2xpbmUoZGF0YSA9IGR1YWwuZHluX2YgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiRyIpLCBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZS8oMTBeNCkpLAogICAgICAgICAgICBjb2xvciA9ICIjNDU3NWI0IikgKwogIGdlb21fcG9pbnQoZGF0YSA9IGR1YWwuZHluX2YgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiRyIgJiByb3dfbnVtYmVyKCkgJSUgMTAwMCA9PSAwKSwgCiAgICAgICAgICAgICBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZS8oMTBeNCkpLCBzaXplID0gMiwgY29sb3IgPSAiIzQ1NzViNCIpICsKICBnZW9tX2xpbmUoZGF0YSA9IGR1YWwuZHluX2NyLCBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobmFtZSA9ICJDb252ZXJzaW9uIHJhdGUiLAogICAgICAgICAgICAgICAgICAgICBzZWMuYXhpcyA9IHNlY19heGlzKH4uKjEwXjQsIG5hbWU9IkdhbWV0b2N5dGUgcGVyIMK1TCIpKSArCiAgbGFicyh4ID0gIlRpbWUgKGRheXMpIikgKwogIHhsaW0oMCwgMjApICsKICB0aGVtZV9idygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpkdWFsX1IucGx0IDwtZ2dwbG90KCkgKwogIGdlb21fbGluZShkYXRhID0gZHVhbC5keW5fZiAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJSIiksIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlLygxMF43KSksCiAgICAgICAgICAgIGNvbG9yID0gIiM0NTc1YjQiKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZHVhbC5keW5fZiAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJSIiAmIHJvd19udW1iZXIoKSAlJSAxMDAwID09IDApLCAKICAgICAgICAgICAgIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlLygxMF43KSksIHNpemUgPSAyLCBjb2xvciA9ICIjNDU3NWI0IikgKwogIGdlb21fbGluZShkYXRhID0gZHVhbC5keW5fY3IsIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlKSkgKwogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIkNvbnZlcnNpb24gcmF0ZSIsCiAgICAgICAgICAgICAgICAgICAgIHNlYy5heGlzID0gc2VjX2F4aXMofi4qMTBeNywgbmFtZT0iUkJDIHBlciDCtUwiKSkgKwogIGxhYnMoeCA9ICJUaW1lIChkYXlzKSIpICsKICB4bGltKDAsIDIwKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKZHVhbF9OLnBsdCA8LWdncGxvdCgpICsKICBnZW9tX2xpbmUoZGF0YSA9IGR1YWwuZHluX2YgJT4lIGZpbHRlcih2YXJpYWJsZSA9PSAiTiIpLCBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZSoxMCksCiAgICAgICAgICAgIGNvbG9yID0gIiM0NTc1YjQiKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZHVhbC5keW5fZiAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJOIiAmIHJvd19udW1iZXIoKSAlJSAxMDAwID09IDApLCAKICAgICAgICAgICAgIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlKjEwKSwgc2l6ZSA9IDIsIGNvbG9yID0gIiM0NTc1YjQiKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBkdWFsLmR5bl9jciwgYWVzKHggPSB0aW1lLCB5ID0gdmFsdWUpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKG5hbWUgPSAiQ29udmVyc2lvbiByYXRlIiwKICAgICAgICAgICAgICAgICAgICAgc2VjLmF4aXMgPSBzZWNfYXhpcyh+LiowLjEsIG5hbWU9IkluZGlzY3JpbWluYXRlIGltbXVuaXR5IikpICsKICBsYWJzKHggPSAiVGltZSAoZGF5cykiKSArCiAgeGxpbSgwLCAyMCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCmR1YWxfVy5wbHQgPC1nZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBkdWFsLmR5bl9mICU+JSBmaWx0ZXIodmFyaWFibGUgPT0gIlciKSwgYWVzKHggPSB0aW1lLCB5ID0gdmFsdWUqMiksCiAgICAgICAgICAgIGNvbG9yID0gIiM0NTc1YjQiKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZHVhbC5keW5fZiAlPiUgZmlsdGVyKHZhcmlhYmxlID09ICJXIiAmIHJvd19udW1iZXIoKSAlJSAxMDAwID09IDApLCAKICAgICAgICAgICAgIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlKjIpLCBzaXplID0gMiwgY29sb3IgPSAiIzQ1NzViNCIpICsKICBnZW9tX2xpbmUoZGF0YSA9IGR1YWwuZHluX2NyLCBhZXMoeCA9IHRpbWUsIHkgPSB2YWx1ZSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobmFtZSA9ICJDb252ZXJzaW9uIHJhdGUiLAogICAgICAgICAgICAgICAgICAgICBzZWMuYXhpcyA9IHNlY19heGlzKH4uKjAuNSwgbmFtZT0iVGFyZ2V0ZWQgaW1tdW5pdHkiKSkgKwogIGxhYnMoeCA9ICJUaW1lIChkYXlzKSIpICsKICB4bGltKDAsIDIwKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCiMgcGxvdCB0b2dldGhlcgpgYGB7cn0KZ2dhcnJhbmdlKGR1YWxfSS5wbHQsIGR1YWxfSWcucGx0LCBkdWFsX0cucGx0LCBkdWFsX1IucGx0LCBkdWFsX04ucGx0LCBkdWFsX1cucGx0LCBucm93ID0gMywgbmNvbCA9IDIsIGFsaWduID0gImh2IiwgbGFiZWxzID0gYygiQSIsICJCIiwgIkMiLCAiRCIsICJFIiwgIkYiKSkKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vZHVhbF9keW4udGlmZiIpLCB1bml0cyA9ICJweCIsIHdpZHRoID0gMjI1MCwgaGVpZ2h0ID0gMjAwMCwgc2NhbGUgPSAxLCBkcGk9MzAwLCBiZyA9ICJ3aGl0ZSIpCmBgYAoKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09IwojIFNpbmdsZSBhbmQgY28taW5mZWN0aW9uIHZlcmlmaWNhdGlvbgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0jCiMgc2luZ2xlIGluZmVjdGlvbgpgYGB7cn0KIyBpbXBvcnQgaW4gYWxsIHNpbmdsZSBpbmZlY3Rpb24gZGF0YQpzaV92YWwubHMgPC0gbGlzdC5maWxlcyhwYXRoID0gaGVyZSgiZGF0YS9zaV92YWxpZGF0aW9uIiksIHBhdHRlcm4gPSAiKi5jc3YiLCBmdWxsLm5hbWVzID0gVCkKCnNpX3ZhbC5kZiA8LSBsYXBwbHkoc2lfdmFsLmxzLCByZWFkLmNzdikKc2lfdmFsLmRmIDwtIGRvLmNhbGwocmJpbmQsIHNpX3ZhbC5kZikKCiMgZ2V0IG1heCBmaXRuZXNzIGZyb20gc2ltdWxhdGlvbi4gbGVmdCBqb2luIHdpdGggc2lfb3B0CnNpX29wdC5kZiA8LSByZWFkLmNzdihoZXJlKCJkYXRhL3NpX29wdC5jc3YiKSkKCiMgd2UgY2FuIHNlZSB0aGF0IGFsbCBvZiB0aGUgcmFuZG9tbHkgc2ltdWxhdGVkIG1vZGVscyBoYXZlIGEgZml0bmVzcyB2YWx1ZSB0aGF0IGlzIGxlc3MgdGhhbiB0aGUgb3B0aW1pemVkIG1vZGVsCnNpX3ZhbC5kZjIgPC0gc2VsZWN0KHNpX3ZhbC5kZiwgVjEsIGlkKSAlPiUKICBsZWZ0X2pvaW4oc2lfb3B0LmRmLCBieSA9YygiaWQiID0gImlkIikpICU+JSAKICBtdXRhdGUoZml0bmVzc19kaWZmZXJlbmNlID0gZml0bmVzc18yMCAtIFYxKSAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChlel9sYWJlbCwgaWRfc2ksIGV6X2xhYmVsX3NpKSwgYnkgPSBjKCJpZCIgPSAiaWRfc2kiKSkKYGBgCgojIyMgTW9kZWwgdmFsaWRhdGlvbgpgYGB7cn0KIyByZWFkIGluIHRoZSByZXN1bHRzIGZpbGUKY2lfdmFsLmxzIDwtIGxpc3QuZmlsZXMocGF0aCA9IGhlcmUoImRhdGEvY2lfdmFsaWRhdGlvbiIpLCBwYXR0ZXJuID0gIiouY3N2IiwgZnVsbC5uYW1lcyA9IFQpCmNpX3ZhbC5sczIgPC0gbGFwcGx5KGNpX3ZhbC5scywgcmVhZC5jc3YpCmNpX3ZhbC5kZiA8LSBkby5jYWxsKHJiaW5kLCBjaV92YWwubHMyKQoKY2lfdmFsLmRmMgpjaV92YWwuZGYyIDwtIGNpX3ZhbC5kZiAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChlel9sYWJlbCwgbGFiZWxfY2ksIGV6X2xhYmVsKSwgYnkgPSBjKCJsYWJlbCIgPSAibGFiZWxfY2kiKSkKYGBgCgojIHBsb3QKYGBge3J9CnNpX3ZhbC5wbHQgPC0gZ2dwbG90KGRhdGEgPSBzaV92YWwuZGYyLCBhZXMoeCA9IGZpdG5lc3NfZGlmZmVyZW5jZSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gNTApICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICIjZmM4ZDU5IikgKwogIGZhY2V0X3dyYXAofmV6X2xhYmVsX3NpLCBzY2FsZXMgPSAiZnJlZSIsIG5jb2wgPSAzKSArCiAgbGFicyh4ID0gIk9wdGltaXplZCBmaXRuZXNzIC0gcmFuZG9tIGZpdG5lc3MiLCB5ID0gIkZyZXF1ZW5jeSIpICsKICB0aGVtZV9idygpCgpjaV92YWwucGx0IDwtIGdncGxvdChkYXRhID0gY2lfdmFsLmRmMiwgYWVzKHggPSBWMSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gNTApICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICIjZmM4ZDU5IikgKwogIGZhY2V0X3dyYXAofmV6X2xhYmVsLCBzY2FsZXMgPSAiZnJlZSIsIG5jb2wgPSA0KSArCiAgbGFicyh4ID0gIkZpdG5lc3MgZGlmZmVyZW5jZSBiZXR3ZWVuXG5vcHRpbWl6ZWQgYW5kIHJhbmRvbSBzdHJhaW4iLCB5ID0gIkZyZXF1ZW5jeSIpICsKICB0aGVtZV9idygpCgpnZ2FycmFuZ2Uoc2lfdmFsLnBsdCwgY2lfdmFsLnBsdCwgYWxpZ24gPSAiaHYiLCBsYWJlbHMgPSBjKCJBIiwgIkIiKSwgd2lkdGhzID0gYygzLDQpKQpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wbG9zLWJpby92YWxpZGF0aW9uLnRpZmYiKSwgdW5pdHMgPSAicHgiLCB3aWR0aCA9IDIyNTAsIGhlaWdodCA9IDEzMDAsIHNjYWxlID0gMS42LCBkcGk9MzAwLCBiZyA9ICJ3aGl0ZSIpCmBgYAoKIz09PT09PT09PT09PT09PT09PT09PT09PT0jCiMgTW9udGUgY2FybG8gZHluYW1pY3Mgc3VwcGxlbWVudGFyeQojPT09PT09PT09PT09PT09PT09PT09PT09PSMKIyBydW4gY29kZSBpbiByZXBvcnQgMTYKYGBge3J9Cm1jX2R5bl9hIDwtIGdncGxvdCgpICsKICBnZW9tX2xpbmUoZGF0YSA9IHJlZmVyZW5jZS5kZiwgYWVzKHggPSB0aW1lLCB5ID0gY3IpKSArCiAgZ2VvbV9yaWJib24oZGF0YSA9IGRpZmYuZGYsIGFlcyh4ID0gdGltZSwgeW1pbiA9IGNyX2JvdCwgeW1heCA9IGNyX3RvcCksIGFscGhhID0gMC41LCBmaWxsID0gIiNmYzhkNTkiKSArCiAgZmFjZXRfd3JhcCh+Y3VlLCBuY29sID0gMikgKwogIGxhYnMoeCA9ICJUaW1lIChkYXlzKSIsIHkgPSAiQ29udmVyc2lvbiByYXRlIikgKwogIHRoZW1lX2J3KCkKICAKIyBwbG90IGZpdG5lc3MgdGltZXNlcmllcy4gV2hlbiBpZiB0aW5lc3MgbG9zdD8gQXQgdGhlIGxhdHRlciBwYXJ0Cm1jX2R5bl9iICA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGRhdGEgPSByZWZlcmVuY2UuZGYsIGFlcyh4ID0gdGltZSwgeSA9IHRhdSkpICsKICBnZW9tX3JpYmJvbihkYXRhID0gZGlmZi5kZiwgYWVzKHggPSB0aW1lLCB5bWluID0gdGF1X2JvdCwgeW1heCA9IHRhdV90b3ApLCBhbHBoYSA9IDAuNSwgZmlsbCA9ICIjZmM4ZDU5IikgKwogIGZhY2V0X3dyYXAofmN1ZSwgbmNvbCA9IDIpICsKICBsYWJzKHggPSAiVGltZSAoZGF5cykiLCB5ID0gIlRyYW5zbWlzc2lvbiBwb3RlbnRpYWwiKSArCiAgdGhlbWVfYncoKQoKZ2dhcnJhbmdlKG1jX2R5bl9hLCBtY19keW5fYiwgbmNvbCA9IDEsIGFsaWduID0gInYiLCBsYWJlbHMgPSBjKCJBIiwgIkIiKSkKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvcGxvcy1iaW8vTUNfZHluLnRpZmYiKSwgdW5pdHMgPSAicHgiLCB3aWR0aCA9IDIwMDAsIGhlaWdodCA9IDI2MDAsIHNjYWxlID0gMSwgZHBpPTMwMCwgYmcgPSAid2hpdGUiKQpgYGAKCgoK